OWASP top 10
Deep walkthrough of each OWASP Top 10 2021 category with example exploits, fixes, and how to detect them in code review.
How The List Is Built
OWASP collects data from companies that run vulnerability scanners and pen tests, then ranks risk categories by frequency, exploitability, and impact. It is not a list of the worst possible bugs, it is a list of the bugs most commonly found in real apps. The current edition is 2021. A 2025/2026 update is in draft.
The categories are intentionally broad because the goal is to cover patterns, not specific CVEs. "Injection" covers SQL, NoSQL, command, LDAP, XPath, header injection. Once you understand the category, the specific variants follow.
A01: Broken Access Control
Number one for a reason. It is the most common, easiest to introduce, and hardest to test for automatically.
Examples.
- IDOR (Insecure Direct Object Reference):
GET /api/invoices/123. User A's invoice is 123, user B requests it and gets it back. Server checked the user was logged in but not whether they own invoice 123. - Missing function-level authorization: regular user POSTs to
/admin/delete_userand it works because the endpoint only checked authentication, not role. - JWT manipulation: changing the role claim to admin when the server doesn't re-verify.
- Path traversal:
GET /files?name=../../etc/passwd.
Fix patterns.
- Default deny. Authorization checks are explicit on every endpoint.
- Object-level checks. Always verify the user can act on this specific object, not just that they can act on objects of this type.
- Centralized policy. Cassandra Sentinel, OPA, or framework-level guards. Not scattered if-statements.
- Tests. Write tests where user A tries to access user B's data and verify the response is 403.
A02: Cryptographic Failures
Sensitive data not protected at rest or in transit.
Examples.
- HTTP instead of HTTPS for sensitive flows.
- Passwords stored as plain text or MD5/SHA1.
- AES in ECB mode (penguin meme).
- Hardcoded encryption keys in source.
- Weak random in token generation (using Math.random() for security tokens).
Fix patterns.
- HTTPS everywhere, with HSTS.
- Passwords with bcrypt, scrypt, or Argon2. Never MD5/SHA1, never plain SHA256. Use the library's defaults for cost parameters.
- AES-GCM or ChaCha20-Poly1305 for symmetric encryption.
- KMS or HSM for key management, not env vars in plain text.
- Cryptographically secure RNG:
crypto.randomBytes,secrets.token_bytes, neverMath.random().
A03: Injection
SQL injection is 25 years old and still in the top three. Plus NoSQL, command, LDAP, header, template injection.
// Vulnerable
const query = `SELECT * FROM users WHERE name = '${name}'`;
// Safe
const query = "SELECT * FROM users WHERE name = $1";
db.query(query, [name]);Fix patterns.
- Parameterized queries / prepared statements. Every database client supports them.
- ORM or query builder. Don't string-concat SQL.
- For command injection: avoid shell=True, pass args as array (
execFilenotexec). - For LDAP/XPath/etc: use library escaping functions.
- Input validation as defense in depth, not the primary defense.
NoSQL injection is real. MongoDB queries take objects, and if you accept {"$gt": ""} as a password value, the query matches everything. Always validate the type of incoming data.
A04: Insecure Design
New in 2021. The architecture itself enables abuse even if every line of code is correct.
Examples.
- Registration with no rate limit, no CAPTCHA, no email verification. Spam bots create millions of accounts.
- Password reset that emails the new password instead of a one-time link.
- Money transfer endpoint with no confirmation step or 2FA.
- Cache that includes per-user data with the wrong key (data leak between users).
Fix patterns.
- Threat model new features before writing code. STRIDE or just "how would I abuse this."
- Rate limiting on every public endpoint, not just login.
- 2FA for sensitive actions, not just login.
- Defense in depth. Assume any single layer can be bypassed.
This category is where a security-minded engineer adds the most value. Code bugs get caught by tools. Design bugs only get caught by someone thinking adversarially during design.
A05: Security Misconfiguration
The boring one that causes the most real breaches.
Examples.
- Default credentials (admin/admin) left in production.
- Verbose error messages with stack traces in production.
- S3 buckets public by default.
- Debug endpoints (/actuator, /admin) exposed.
- Missing security headers (CSP, HSTS, X-Frame-Options).
- CORS allow-all (
Access-Control-Allow-Origin: *with credentials). - Cloud accounts with no MFA on root.
Fix patterns.
- Infrastructure as code. Review configuration like code.
- Security baselines. CIS benchmarks for AWS, GCP, Azure, Kubernetes.
- Automated scanners. Trivy, Checkov, kube-bench.
- Strip unnecessary services. If you don't use it, disable it.
- Generic error pages in production. Detailed errors only in logs.
A06: Vulnerable and Outdated Components
You ship the bugs in your dependencies.
Examples.
- log4shell (log4j 2.x, CVE-2021-44228). RCE via JNDI lookup in log strings. Affected millions of apps.
- Equifax (Apache Struts CVE-2017-5638). RCE in Content-Type header parsing. 147M records lost.
- Codecov supply chain attack (2021). Compromised bash uploader exfiltrated env vars from CI.
Fix patterns.
- Dependency scanning in CI.
npm audit,pip-audit, Dependabot, Snyk, Trivy. - SBOM (Software Bill of Materials). Track what you ship.
- Pin versions for reproducibility, but allow security patches.
- Subresource Integrity (SRI) on third-party scripts you load from CDNs.
- Container base image hygiene: distroless, alpine, or minimal images.
A07: Identification and Authentication Failures
Examples.
- Credential stuffing: attackers try leaked password lists against your login.
- Session fixation: attacker sets a session ID before login, gets it after.
- Password reset that leaks whether an email exists.
- 2FA codes that don't expire or aren't rate-limited.
- Same-session impersonation when admins "log in as" without a new session.
Fix patterns.
- Rate limit login attempts. Account lockout or progressive delays.
- Have I Been Pwned API to check leaked passwords on signup.
- Generic responses for "user not found" vs "wrong password" (debatable, modern wisdom is that this is security theater).
- TOTP or WebAuthn for 2FA. SMS is weakest but better than nothing.
- Session rotation on login. New session ID after auth.
A08: Software and Data Integrity Failures
New in 2021. The supply chain problem.
Examples.
- Auto-update without signature verification. Attacker MITMs the update server, pushes malware.
- Insecure deserialization. Java/PHP/Python deserialization gadgets give RCE.
- CI/CD pipelines that trust everything: PR from forks runs internal scripts with secrets.
- npm packages with thousands of transitive deps, one of which is malicious.
Fix patterns.
- Sign artifacts. Verify signatures on update. cosign, sigstore.
- SLSA framework for supply chain integrity.
- Limit CI privileges. Forks don't get secrets.
- Avoid deserializing untrusted data. If you must, use a safe format (JSON not pickle).
A09: Security Logging and Monitoring Failures
You can't respond to what you can't see. Median breach goes undetected for 200+ days.
Log these.
- Authentication events: success, failure, lockout.
- Authorization failures: 403 responses with context.
- Admin actions: who did what.
- Sensitive data access: who read which records.
- Anomalies: 100 failed logins from one IP, 10x normal traffic.
Ship to a SIEM or at least a log aggregation tool with alerting. The Equifax breach was preventable: the IDS that would have caught the exfiltration was offline because its certificate had expired.
Don't log secrets. Auth tokens, passwords, PII. Sanitize logs.
A10: Server-Side Request Forgery
Covered in detail in the CSRF/XSS/SSRF chapter. Promoted to top 10 because of Capital One and the rise of cloud metadata as a credential source.
Defense recap.
- URL allowlist of destination domains.
- Block private IP ranges after DNS resolution.
- IMDSv2 on AWS.
- Egress proxy with allow-list.
Beyond The Top 10
OWASP also publishes specialized lists.
- API Security Top 10 (2023). Different risks for APIs: broken object-level auth, broken authentication, excessive data exposure, lack of rate limiting, unrestricted resource consumption.
- Mobile Top 10. Insecure data storage, insecure communication, code tampering, reverse engineering.
- LLM Top 10 (2023). Prompt injection, insecure output handling, training data poisoning, model DoS, sensitive info in responses. Critical in 2026.
Use the right list for what you're building.
How To Use The List In Practice
Code review. When reviewing a PR, walk the diff against the top 10. New endpoint? Check access control. Touching DB? Check injection. Adding a dependency? Check vuln scanner.
Threat modeling. For a new feature, list which top 10 categories apply. A new login endpoint touches A01, A02, A07. A new file upload touches A01, A03, A05, A06.
Pen test scoping. Tell your pen testers "cover the OWASP top 10 at minimum, plus our app-specific concerns."
Interview answers. When asked "how would you secure this app," frame the answer around the top 10. Shows you have a systematic approach, not just trivia.
Common Pitfalls
- Treating it as a checklist. Cover the categories, don't tick boxes.
- Focusing only on injection and ignoring access control. A01 is more common.
- Skipping logging because it doesn't feel like security. It is what enables response.
- Trusting "we use a framework" as security. Frameworks help with some categories, not all.
Interview Soundbites
- "Top 10 is the consensus list of web app risks. Memorize categories, not order. Walk a PR against them in code review."
- "Broken access control is number one. Default deny, object-level checks, tested with cross-user scenarios."
- "Insecure design is the architecture problem. Threat model before you code, rate limit everything."
- "Logging failures are how breaches go undetected for months. Log auth events, ship to a SIEM, alert on anomalies."
Learn more
- DocsOWASP Top 10 2021OWASP
- Docs
- Docs
- DocsOWASP LLM Top 10OWASP