Security is critical in a health app. This guide is concise—read it!
DO NOT open public GitHub issues for security bugs.
Email maintainers privately with:
- Description & steps to reproduce
- Impact assessment
- Suggested fix (optional)
Timeline: 48-hour acknowledgment, weekly updates.
# Already in .gitignore
.env, .env.localRequired variables:
PORT=8080
MONGO_URI=mongodb+srv://username:[email protected]/dbname
JWT_SECRET=min_32_char_random_string
GROQ_API_KEY=gsk_xxx
GEMINI_API_KEY=AIzaSyxxx
HUGGINGFACEHUB_API_KEY=hf_xxx
GOOGLE_CLIENT_ID=xxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX_xxx
GOOGLE_REDIRECT_URI=http://localhost:8080/api/oauth/callback
REPORT_API=key
REPORT_TEMPLATE_ID=5b077b23e86a4726// Good ✓
const secret = process.env.JWT_SECRET;
if (!secret) throw new Error('Missing JWT_SECRET');
// Bad ✗
const secret = 'hardcoded-key';
console.log('Using key:', secret);- Rotate immediately
- Force push:
git reset HEAD~1, remove .env, commit,git push --force-with-lease - Use BFG to scrub history
import bcryptjs from 'bcryptjs';
const hashed = await bcryptjs.hash(password, 10);const token = jwt.sign({ id: userId }, process.env.JWT_SECRET, { expiresIn: '24h' });const token = req.headers.authorization?.split(' ')[1];
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;router.get('/api/medicines', authMiddleware, getMedicines);const token = localStorage.getItem('token');
if (!token) return <Navigate to="/login" />;// Good ✓
const medicines = await Medicine.find({ userId: req.user.id });
// Bad ✗
const medicines = await Medicine.find({ userId: req.body.userId });import { body, validationResult } from 'express-validator';
app.post('/api/medicines',
body('name').trim().notEmpty().escape(),
body('dosage').isNumeric(),
(req, res) => {
if (!validationResult(req).isEmpty()) {
return res.status(400).json({ errors: validationResult(req).array() });
}
}
);userSchema.methods.toJSON = function() {
const obj = this.toObject();
delete obj.password;
return obj;
};// Safe - prevents NoSQL injection
const user = await User.findById(userId);app.use(cors({
origin: ['http://localhost:5173', 'https://yourdomain.com'],
credentials: true
}));const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5 // 5 attempts per 15 min
});
app.post('/api/auth/login', loginLimiter, login);io.use((socket, next) => {
const decoded = jwt.verify(socket.handshake.auth.token, process.env.JWT_SECRET);
socket.userId = decoded.id;
next();
});
// Send to specific user: io.to(`user_${userId}`).emit('notification', data);const upload = multer({
limits: { fileSize: 10 * 1024 * 1024 }, // 10MB
fileFilter: (req, file, cb) => {
if (file.mimetype === 'application/pdf') cb(null, true);
else cb(new Error('PDF only'));
}
});// Bad ✗
catch (error) { res.json({ error: error.message }); }
// Good ✓
catch (error) {
console.error('Details:', error);
res.status(500).json({ error: 'Operation failed' });
}npm audit # Find issues
npm audit fix # Auto-fix
npm outdated # See old packages
npm update # Update packages- Check GitHub repo reputation
- Verify recent updates
- Avoid unmaintained packages
Safe packages: express, jsonwebtoken, mongoose, bcryptjs, cors, socket.io, @langchain/*
npm install husky --save-dev
npx husky install
# Create .husky/pre-commit
echo '#!/bin/sh
if git diff --cached --name-only | grep -E "\.env"; then
echo "Error: .env detected"
exit 1
fi' > .husky/pre-commit
chmod +x .husky/pre-commitgit diff --cached # Check before committingFrontend:
- No API keys in code
- Routes protected with auth check
- Input validated before API calls
- No console.log of sensitive data
- Uses
https://for APIs
Backend:
- authMiddleware on sensitive routes
- Queries filter by
userId - Input validated (express-validator)
- Passwords hashed
- JWT tokens signed & verified
- Rate limit on auth endpoints
- File uploads validated
- Socket.IO authenticated
Both:
- No secrets in commits
- No hardcoded keys/URLs
- Dependencies from trusted sources
- Good error handling
| Issue | Fix |
|---|---|
| Credential leak | Use .env + .gitignore |
| Injection attacks | Use express-validator, parameterized queries |
| Weak passwords | Hash with bcryptjs (10 rounds) |
| Data leaks | Filter queries by userId |
| Unauthorized access | Require JWT + authMiddleware |
| Brute force | Rate limit auth endpoints |
| Old packages | npm audit, npm update |
| Secrets in Git | Pre-commit hooks, .gitignore |
For security issues: Email maintainers privately
For questions: See CONTRIBUTING.md
Last updated: December 2025