6.6 KiB
6.6 KiB
Vulnerability Patterns Reference
Secure vs vulnerable code patterns organized by category. Each pattern shows the vulnerability and its remediation.
Input Validation
SQL Injection
// VULNERABLE
const query = `SELECT * FROM users WHERE email = '${userEmail}'`;
// SECURE - parameterized queries
const query = 'SELECT * FROM users WHERE email = ?';
db.execute(query, [userEmail]);
XSS (Cross-Site Scripting)
// VULNERABLE - direct HTML insertion
element.innerHTML = userInput;
// SECURE - use textContent or sanitize
element.textContent = userInput;
// OR for rich content
element.innerHTML = DOMPurify.sanitize(userInput);
Command Injection
// VULNERABLE
exec(`convert ${userFilename} output.png`);
// SECURE - parameterized or allowlist
execFile('convert', [userFilename, 'output.png']);
Path Traversal
// VULNERABLE
const filePath = `/uploads/${userFileName}`;
// SECURE - validate and normalize
const safeName = path.basename(userFileName);
const filePath = path.join('/uploads', safeName);
if (!filePath.startsWith('/uploads/')) {
throw new Error('Invalid path');
}
XXE (XML External Entity)
// VULNERABLE
const parser = new DOMParser();
const doc = parser.parseFromString(xmlInput, 'text/xml');
// SECURE - disable external entities
const parser = new DOMParser({
locator: {},
errorHandler: {},
entityResolver: () => null, // Disable DTD processing
});
Authentication & Sessions
Password Storage
// VULNERABLE - plain text or weak hash
const hash = md5(password);
// SECURE - bcrypt/argon2 with salt
const hash = await bcrypt.hash(password, 12);
Session Management
// VULNERABLE - predictable session IDs
const sessionId = userId + Date.now();
// SECURE - cryptographically random
const sessionId = crypto.randomBytes(32).toString('hex');
// Security attributes
res.cookie('session', sessionId, {
httpOnly: true,
secure: true, // HTTPS only
sameSite: 'strict',
maxAge: 3600000, // 1 hour
});
JWT Handling
// VULNERABLE - no signature verification
const payload = JSON.parse(atob(token.split('.')[1]));
// SECURE - verify signature
const payload = jwt.verify(token, SECRET_KEY, {
algorithms: ['HS256'], // Specify allowed algorithms
issuer: 'your-app',
audience: 'your-api',
});
Password Reset
// VULNERABLE - predictable tokens
const resetToken = userId + '-' + Date.now();
// SECURE - cryptographically random with expiry
const resetToken = crypto.randomBytes(32).toString('hex');
await db.execute(
'INSERT INTO reset_tokens (user_id, token, expires_at) VALUES (?, ?, ?)',
[userId, await bcrypt.hash(resetToken, 10), Date.now() + 3600000]
);
Authorization
Broken Access Control
// VULNERABLE - client-side only check
if (user.isAdmin) {
// show admin panel
}
// SECURE - server-side enforcement
app.get('/admin/users', requireAdmin, (req, res) => {
if (!req.user?.isAdmin) {
return res.status(403).json({ error: 'Forbidden' });
}
// Admin operation
});
IDOR (Insecure Direct Object Reference)
// VULNERABLE - no ownership check
app.get('/api/documents/:id', async (req, res) => {
const doc = await db.getDocument(req.params.id);
res.json(doc);
});
// SECURE - verify ownership
app.get('/api/documents/:id', async (req, res) => {
const doc = await db.getDocument(req.params.id);
if (doc.userId !== req.user.id && !req.user.isAdmin) {
return res.status(403).json({ error: 'Forbidden' });
}
res.json(doc);
});
Privilege Escalation
// VULNERABLE - role from client input
app.post('/api/users', async (req, res) => {
const user = await createUser({
...req.body, // Includes role: 'admin' from malicious client
});
});
// SECURE - explicit allowlist
app.post('/api/users', async (req, res) => {
const allowedFields = ['name', 'email', 'password'];
const userData = pick(req.body, allowedFields);
const user = await createUser({
...userData,
role: 'user', // Server controls role
});
});
Cryptography
Weak Algorithms
// VULNERABLE - deprecated algorithms
const hash = crypto.createHash('md5').update(data).digest('hex');
const cipher = crypto.createCipher('des', key);
// SECURE - modern algorithms
const hash = crypto.createHash('sha256').update(data).digest('hex');
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
Hardcoded Secrets
// VULNERABLE
const API_KEY = 'sk-1234567890abcdef';
const DB_PASSWORD = 'admin123';
// SECURE - environment variables
const API_KEY = process.env.API_KEY;
const DB_PASSWORD = process.env.DB_PASSWORD;
if (!API_KEY || !DB_PASSWORD) {
throw new Error('Missing required environment variables');
}
Insufficient Randomness
// VULNERABLE - predictable
const token = Math.random().toString(36);
// SECURE - cryptographically secure
const token = crypto.randomBytes(32).toString('hex');
Data Exposure
Sensitive Data in Logs
// VULNERABLE
logger.info('User login', { email, password, ssn });
// SECURE - redact sensitive fields
logger.info('User login', {
email,
password: '[REDACTED]',
ssn: '[REDACTED]',
});
Error Message Disclosure
// VULNERABLE - exposes internals
catch (err) {
res.status(500).json({ error: err.stack });
}
// SECURE - generic message
catch (err) {
logger.error('Internal error', err);
res.status(500).json({ error: 'Internal server error' });
}
Timing Attacks
// VULNERABLE - early exit leaks info
if (user.password !== inputPassword) {
return false;
}
// SECURE - constant-time comparison
return crypto.timingSafeEqual(
Buffer.from(user.password),
Buffer.from(inputPassword)
);
Quick Reference
| Category | Vulnerable Pattern | Secure Pattern |
|---|---|---|
| SQL Injection | String concatenation | Parameterized queries |
| XSS | innerHTML with user input | textContent or DOMPurify |
| Command Injection | exec() with user input | execFile() with array args |
| Path Traversal | Direct path concat | path.basename + prefix check |
| Password Storage | MD5/SHA1/plain | bcrypt (cost 12+) or argon2 |
| Session IDs | Predictable (Date.now) | crypto.randomBytes(32) |
| JWT | Skip verification | jwt.verify() with algorithm |
| Access Control | Client-side only | Server-side on every request |
| IDOR | No ownership check | Verify user owns resource |
| Secrets | Hardcoded in code | Environment variables |
| Error Messages | Stack traces to users | Generic error + log details |