Fixing Vulnerabilities
Practical guides and code examples for fixing common security vulnerabilities. Learn remediation techniques, prevention strategies, and best practices for secure code development.
🗃️ SQL Injection Prevention
🚨 NEVER DO THIS
Vulnerable Code:
// VULNERABLE - String concatenation const query = "SELECT * FROM users WHERE id = " + userId; db.query(query);
✅ Prepared Statements
Node.js + MySQL:
const query = "SELECT * FROM users WHERE id = ?";
db.query(query, [userId], (err, results) => {
// Safe from SQL injection
});Python + SQLite:
cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))
results = cursor.fetchall()🔧 ORM Solutions
Prisma ORM:
const user = await prisma.user.findUnique({
where: { id: userId }
});TypeORM:
const user = await userRepository.findOne({
where: { id: userId }
});🛡️ Input Validation
Type Checking:
// Ensure userId is a number
const userId = parseInt(req.params.id);
if (isNaN(userId)) {
return res.status(400).json({ error: 'Invalid ID' });
}Sanitization:
// Remove dangerous characters const cleanInput = input.replace(/[<>'"&]/g, ''); // Or use a library like validator.js const sanitized = validator.escape(dirtyInput);
🌐 Cross-Site Scripting (XSS) Protection
🚨 DANGEROUS PATTERNS
// VULNERABLE - Direct HTML insertion const html = "<div>" + userInput + "</div>"; element.innerHTML = html;
✅ Output Encoding
HTML Context:
// Use textContent instead of innerHTML
element.textContent = userInput;
// Or escape HTML entities
const safeHTML = escapeHtml(userInput);
element.innerHTML = `<div>${safeHTML}</div>`;🔧 Content Security Policy
HTTP Headers:
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';
🛡️ Framework Protection
React:
// React automatically escapes JSX
const element = <div>{userInput}</div>;
// For dangerouslySetInnerHTML, sanitize first
const sanitizedHTML = DOMPurify.sanitize(dirtyHTML);
<div dangerouslySetInnerHTML={{__html: sanitizedHTML}} />🧹 Input Sanitization Libraries
DOMPurify
HTML sanitization
validator.js
Input validation
xss
XSS filtering
sanitize-html
HTML cleaner
🔐 Authentication & Authorization Fixes
Session Management
Secure Session Config
app.use(session({
name: 'sessionId', // Don't use default
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: true, // HTTPS only
httpOnly: true, // Prevent XSS
maxAge: 30 * 60 * 1000 // 30 minutes
}
}));JWT Best Practices
const token = jwt.sign(
{ userId, role },
process.env.JWT_SECRET,
{
expiresIn: '1h',
issuer: 'your-app',
audience: 'your-users'
}
);Password Security
Strong Hashing
const bcrypt = require('bcrypt');
const saltRounds = 12;
const hash = await bcrypt.hash(password, saltRounds);
const isValid = await bcrypt.compare(password, hash);Password Policies
const isStrong = password.length >= 12 && /[A-Z]/.test(password) && /[a-z]/.test(password) && /[0-9]/.test(password) && /[^A-Za-z0-9]/.test(password);
🔒 Authorization Patterns
Role-Based Access:
const authorize = (roles) => (req, res, next) => {
if (!roles.includes(req.user.role)) {
return res.status(403).json({ error: 'Access denied' });
}
next();
};
// Usage
app.get('/admin', authorize(['admin']), handler);Resource-Based Access:
const canAccess = (user, resource, action) => {
// Check ownership or permissions
return resource.ownerId === user.id ||
user.permissions.includes(action);
};
if (!canAccess(user, post, 'edit')) {
throw new ForbiddenError();
}📁 File Upload Security
File Type Validation
MIME Type Checking
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
const fileType = await fileTypeFromBuffer(buffer);
if (!allowedTypes.includes(fileType.mime)) {
throw new Error('Invalid file type');
}Extension Validation
const allowedExts = ['.jpg', '.jpeg', '.png', '.gif'];
const ext = path.extname(filename).toLowerCase();
if (!allowedExts.includes(ext)) {
throw new Error('Invalid file extension');
}Security Measures
Random Filenames
const crypto = require('crypto');
const randomName = crypto.randomBytes(16).toString('hex');
const extension = path.extname(originalName);
const safeName = `${randomName}${extension}`;Size Limits
const MAX_SIZE = 5 * 1024 * 1024; // 5MB
if (file.size > MAX_SIZE) {
throw new Error('File too large');
}🚨 Directory Traversal Prevention
// DANGEROUS - Allows directory traversal const filePath = path.join(uploadDir, req.body.filename); // SAFE - Use basename and validate const filename = path.basename(req.body.filename); const safePath = path.join(uploadDir, filename); // Even safer - Generate your own filename const safeName = generateSafeFilename(); const safePath = path.join(uploadDir, safeName);
📦 Dependency Vulnerability Management
Regular Updates
• Run
npm audit weekly• Update dependencies monthly
• Test after updates
• Use
npm audit fixAutomated Tools
• Dependabot (GitHub)
• Snyk
• npm audit
• OWASP Dependency Check
Lock Files
• Commit package-lock.json
• Use exact versions
• Regular integrity checks
• CI/CD validation
🔄 Update Strategy
Patch Updates (Safe):
- • Bug fixes only
- • No breaking changes
- • Automated updates OK
- • Low testing required
Major Updates (Careful):
- • Breaking changes possible
- • Manual review required
- • Full test suite needed
- • Deployment planning
Quick Fixes
SQL Injection:
Use prepared statements
XSS:
Escape output, CSP headers
Auth:
Strong passwords, MFA
Testing Fixes
• Unit tests for validation
• Integration tests for auth
• Security regression tests
• Penetration testing
• Code review checklist
Prevention Tools
🛡️ ESLint Security
🔍 SAST Scanners
📊 Dependency Checkers
🚨 Runtime Protection
