L29 · The OWASP Top 10, mapped
Module 5: Web Application Security · ~20 min · Lesson 29 of 71
🎯 What you'll learn
- What OWASP is, and what the Top 10 is (and isn't): an awareness list, not a standard
- How the list is built from vulnerability data plus a community survey, and why that matters
- The 2021 and 2025 lists side by side: what moved, what merged, and what's new
- Where each category shows up in a typical API stack, and which lesson in this course covers it
🔥 Why this matters
A penetration test of your accounts API comes back with twelve findings. Three are tagged "A03:2021-Injection". The same week, your AppSec team publishes a new standard that says "no open A05:2025 findings at release". Is that the same thing? (Yes: Injection moved from 3rd to 5th.) The OWASP Top 10 is the shared vocabulary of auditors, scanners, pen testers and regulators, so you'll see these labels on every report. This lesson gives you the map, so the rest of Module 5 has a place to hang each topic.
1. What OWASP and the Top 10 are
The Open Worldwide Application Security Project (OWASP) is a non-profit foundation that publishes free security material: the Top 10, cheat sheets, testing guides, and tools such as ZAP (now maintained outside OWASP) and Dependency-Check. It was called the Open Web Application Security Project until 2023.
The OWASP Top 10 is a ranked list of the ten most critical categories of web application security risk. Editions came out in 2003, 2004, 2007, 2010, 2013, 2017, 2021 and 2025, so roughly every three to four years. Each entry has an ID like A01:2021: the rank, then the edition year. Always quote the year, because the same number means different things in different editions.
OWASP calls it an awareness document: a list meant to get the biggest problems in front of developers and managers. It is not a checklist, a testing standard, or a certification. "We're Top 10 compliant" doesn't mean anything precise. For testable requirements, OWASP points you at the Application Security Verification Standard (ASVS), the first deep dive below.
2. How the list is built
Each category is a bucket of CWEs. A CWE (Common Weakness Enumeration) is MITRE's catalog of weakness types, such as CWE-89 (SQL injection) or CWE-639 (authorization bypass through a user-controlled key). Scanners and pen testers tag findings with CWEs, and OWASP collects those tagged findings from contributing organizations.
CONTRIBUTED DATA COMMUNITY SURVEY
(security vendors, consultancies, (practitioners: "what worries
bug bounty, in-house testing) you that tools can't see yet?")
│ │
│ 1. findings tagged with CWEs │
▼ │
┌──────────────────────────────┐ │
│ CWE-89, CWE-79, CWE-639, ... │ │
│ grouped by root cause into │ │
│ categories │ │
└──────────────┬───────────────┘ │
│ 2. rank each category: │
│ how many tested apps │
│ had it (incidence rate) │
│ + exploit and impact │
│ scores from CVE data │
▼ ▼
8 categories from data + 2 promoted by the survey
│
▼ 3. public draft, review, release
THE TOP 10 (A01 ... A10)
Three consequences are worth remembering:
- Rank is mostly about how common, not how damaging. The key number is incidence rate: the share of tested applications with at least one instance of the category. In 2021, 94% of applications were tested for some form of broken access control, and it had more occurrences (over 318,000) than any other category. That's why it's A01, not because each instance is the worst possible bug.
- Data lags reality. Tools find what they're built to find. Supply chain attacks and logging gaps are hard to detect with a scanner, which is why the survey exists: to promote risks that practitioners see but the data under-counts.
- Categories are root causes, not attacks. "Cryptographic Failures" replaced 2017's "Sensitive Data Exposure" because exposure is the symptom; the cause is usually missing or weak crypto.
3. 2021 vs 2025: what changed
The 2025 edition was announced in November 2025 (first as a release candidate). The ranks and
names below match OWASP's 2025 pages; per-category CWE lists may still get editorial tweaks, so check
owasp.org/Top10/2025 when you need the exact mapping.
2021 2025
A01 Broken Access Control ──┬───▶ A01 Broken Access Control
A10 Server-Side Request ────┘ (SSRF now lives here)
Forgery (SSRF)
A05 Security Misconfig. ────────▶ A02 Security Misconfiguration
A06 Vulnerable & Outdated ──────▶ A03 Software Supply Chain
Components (widened) Failures
A02 Cryptographic Failures ─────▶ A04 Cryptographic Failures
A03 Injection (incl. XSS) ──────▶ A05 Injection
A04 Insecure Design ────────────▶ A06 Insecure Design
A07 Identification and ─────────▶ A07 Authentication Failures
Authentication Failures
A08 Software AND Data ──────────▶ A08 Software OR Data
Integrity Failures Integrity Failures
A09 Security Logging and ───────▶ A09 Security Logging and
Monitoring Failures Alerting Failures
(no 2021 category) NEW ▶ A10 Mishandling of
Exceptional Conditions
The big moves:
- SSRF merged into A01. Making the server fetch a URL it shouldn't is, at root, the server acting beyond what the caller is allowed to do. L35 still treats SSRF on its own, because of the cloud metadata endpoint.
- Security Misconfiguration jumped to A02. More of an application's behavior now lives in configuration: gateway plugins, Helm values, IAM policies, feature flags.
- Software Supply Chain Failures (A03) is new and wider. 2021 asked "do you run a library with a known CVE?". 2025 also covers compromised dependencies, build systems and distribution, the SolarWinds and xz-utils kind of attack (L56).
- A09 says "alerting", not "monitoring". Logs nobody is alerted on don't stop anything, as Target found in 2013 (L13).
- A10 is brand new. Mishandling of Exceptional Conditions covers code that behaves insecurely when something unexpected happens: it fails open, leaks a stack trace, or leaves a half-finished transaction behind. It's L04's "fail-safe defaults" turned into a category.
4. The tour, mapped to a typical stack
| 2025 | In one line | What it looks like in practice | Course |
|---|---|---|---|
| A01 Broken Access Control | Callers do things they aren't allowed to | GET /v1/accounts/ACC-1002 returns someone else's account; a "fetch statement from URL" feature reaches internal hosts |
L27, L33, L34, L35, L40 |
| A02 Security Misconfiguration | Insecure defaults and settings | Spring Boot /actuator/env routed through Kong; MongoDB listening without auth; verbose error pages |
L37, L38, L53 |
| A03 Software Supply Chain Failures | Trusting code you didn't write or build | Unpinned pip packages in the Airflow image; a GitHub Action referenced by a moving tag; an unmaintained library | L49, L55–L57 |
| A04 Cryptographic Failures | Missing, weak or misused crypto | TLS off on the hop behind the load balancer; AES-ECB; keys in a ConfigMap | L10, L14–L20 |
| A05 Injection | Data gets interpreted as code | String-built SQL in a reporting job; {"$ne": null} in a Mongo filter; XSS in an admin UI |
L30–L32 |
| A06 Insecure Design | The control was never designed in | No attempt limit on OTP verification; no four-eyes rule on large payments | L04, L05, L42 |
| A07 Authentication Failures | Proving identity goes wrong | Credential stuffing; session not rotated at login; JWT aud not checked |
L18, L21–L26 |
| A08 Software or Data Integrity Failures | Accepting code or data without verifying it | Deserializing untrusted Java objects; unsigned webhook payloads; unverified build artifacts | L17, L36, L49 |
| A09 Security Logging and Alerting Failures | Attacks happen and nobody notices | Failed logins not logged; tokens logged in full; alerts routed to a channel nobody reads | L13, L60, L62 |
| A10 Mishandling of Exceptional Conditions | Errors leave you in an unsafe state | Fraud-check timeout treated as "approved"; stack trace returned to the client | L04 |
You'll notice the API-specific risks (L39) and the LLM risks (L70) have their own OWASP lists. The web Top 10 is the umbrella; those lists zoom in.
5. How to use it, and how not to
Use it as a vocabulary. When a finding is tagged A01, everyone knows the family of problem. It's a good structure for threat-modeling questions (L05) and for a team's secure coding training.
Don't use it as your risk ranking. It's a ranking across hundreds of thousands of applications. Your risk (L02) depends on your system: a batch service with no user input has little injection risk, and a public payments API has a lot of A01 risk.
Don't use it as a test plan. Ten categories can't tell a tester what "done" looks like. Use ASVS requirements, plus abuse cases from your own threat model. Business-logic bugs, such as approving a negative payment, don't fit neatly in any category.
Tag with CWEs, not just categories. Category numbers change every edition; CWE IDs are stable.
A finding tagged CWE-89 maps to A03:2021 and A05:2025 without anyone re-triaging it (second deep
dive).
If you work in financial services or handle card payments, you'll also meet the list in compliance work. PCI DSS v4.0 requirement 6.2.4 asks you to prevent common software attacks (injection, access control, crypto and business-logic attacks among them). Teams commonly use the OWASP lists to show they've covered those attack types.
🧪 Worked example: triaging a pen test report
A (fictional) pen test of api.example.com returns eight findings. Map each to both editions, then
notice what the labels do and don't tell you.
| # | Finding | 2021 | 2025 |
|---|---|---|---|
| 1 | GET /v1/accounts/ACC-1002 with a token for customer C-30582 returns another customer's account |
A01 | A01 |
| 2 | POST /v1/statements/import {"url": "http://169.254.169.254/..."} returns cloud metadata |
A10 | A01 |
| 3 | /actuator/env is reachable through the gateway and shows environment variables |
A05 | A02 |
| 4 | reports-svc builds "... WHERE branch = '" + branch + "'" |
A03 | A05 |
| 5 | The Airflow image installs requests with no version pin from a public index |
A08 (arguably A06) | A03 |
| 6 | The fraud-check client catches a timeout and returns {"decision": "APPROVE"} |
A04 (closest fit) | A10 |
| 7 | 500 failed logins for one account in 2 minutes produced no alert | A09 | A09 |
| 8 | The login endpoint has no rate limit and no lockout | A07 | A07 |
Three things to take from this:
- The fix never depends on the label. Finding 2 is SSRF whether you call it A10:2021 or A01:2025.
- Finding 6 shows why A10:2025 exists. In 2021 it had no clean home; now "fails open on error" is its own named risk, and it's a classic in payments code:
// BEFORE: fails open
try {
return fraudClient.check(payment);
} catch (TimeoutException e) {
log.warn("fraud check timed out, approving");
return Decision.APPROVE; // A10:2025
}
// AFTER: fails safe, and says so
try {
return fraudClient.check(payment);
} catch (TimeoutException e) {
log.error("fraud_check_timeout paymentId={}", payment.id());
metrics.increment("fraud_check_timeout"); // alertable (A09)
return Decision.HOLD_FOR_REVIEW; // no money moves
}
- Severity still comes from your context. Finding 1 on a production customer API is critical; finding 3 on an internal dev cluster may be medium. The category says what, not how bad.
🛠 Try it (optional, ~5 min)
A thought exercise, no tools needed. Take the last 8–10 security findings your team handled (scanner alerts, pen test items, code review comments) and tag each with a 2025 category, keeping your notes free of real hostnames, IDs and secrets.
Then look at the shape of the result:
- Which categories have lots of findings? Usually A02 and A03, because scanners are good at them.
- Which have none? Zero A06, A09 or A10 findings rarely means you're safe. It usually means nothing tests for them. Those empty buckets are where a threat-modeling session (L05) pays off.
- Did any finding not fit? That's often a business-logic bug, and worth a test of its own (L59).
🧠 Key takeaways
- The OWASP Top 10 is an awareness document: shared vocabulary, not a standard or a test plan.
- It's built from CWE-tagged findings ranked by incidence rate, plus two survey-promoted risks.
- 2025 changes: SSRF merged into A01, Misconfiguration up to A02, new A03 Supply Chain, new A10 Mishandling of Exceptional Conditions.
- Always quote the year (A05:2025) and tag findings with CWEs, which don't change between editions.
- Your own risk depends on your system; the category tells you what, not how bad.
📖 Words to know
| Term | Meaning |
|---|---|
| OWASP | Open Worldwide Application Security Project, a non-profit that publishes free AppSec material |
| OWASP Top 10 | A ranked awareness list of the ten most critical web application risk categories |
| Awareness document | A list meant to inform and prioritize, not to be tested or certified against |
| CWE | Common Weakness Enumeration: MITRE's catalog of weakness types, such as CWE-89 |
| Incidence rate | The share of tested applications with at least one instance of a category |
| ASVS | Application Security Verification Standard: OWASP's testable security requirements |
| Software supply chain | Everything between other people's code and your running service: dependencies, build, distribution |
| Exceptional condition | An error or unexpected state (timeout, null, partial failure) the code must handle safely |
| Fail open | Responding to an error by allowing the action, instead of denying it |
⏭ Next time
L30 opens the injection family with the oldest member: SQL injection, how a single quote turns your data into someone else's code, and why parameterized queries end it.
ASVS: turning the Top 10 into requirements you can test
The Top 10 tells you what tends to go wrong. It can't tell a developer what to build or a tester when they're done. That's the job of the OWASP Application Security Verification Standard (ASVS): a catalog of specific, testable security requirements.
The OWASP "three layers"
WHO ASKS OWASP DOCUMENT ANSWERS
──────────────────── ──────────────────────── ─────────────────
managers, auditors ─▶ Top 10 (risks) ─▶ "what goes wrong?"
developers ──▶ Top 10 Proactive ─▶ "what do I build?"
Controls, Cheat Sheets
testers, reviewers ─▶ ASVS (requirements) ─▶ "is it done?"
pen testers ──▶ Web Security Testing ─▶ "how do I test
Guide (WSTG) it?"
The Proactive Controls (latest edition 2024) are the developer-facing flip side of the Top 10: "implement access control", "use cryptography to protect data", "validate all input and handle exceptions", and so on. The Cheat Sheet Series gives the how-to for each topic (there's one on SQL injection prevention you'll meet in L30).
How ASVS is organized
ASVS 5.0.0 was released in May 2025. Its chapters are grouped by area: encoding and sanitization, validation and business logic, API and web services, authentication, session management, authorization, self-contained tokens, OAuth and OIDC, cryptography, configuration, data protection, logging and error handling, and more. Each requirement has an ID and a level:
- Level 1: the baseline every application should meet.
- Level 2: for applications handling sensitive data or transactions. Most financial services apps target this.
- Level 3: for the most critical systems, where compromise would be severe.
Chapter numbers were reorganized between ASVS 4.0.3 (2021) and 5.0.0, so cite requirements with the
version, for example v5.0.0-<chapter>.<section>.<requirement>. The standard recommends this format
for exactly that reason.
Worked example: from finding to acceptance criteria
Finding 1 from the main lesson (another customer's account returned) gets a ticket. A vague ticket says "Fix A01". A useful one turns the ASVS authorization requirements (paraphrased here; quote the real text from the version your team adopts) into checks a reviewer can tick:
TICKET: Enforce object-level authz on accounts-api
Maps to: A01:2025, CWE-639, ASVS 5.0 authorization chapter (L2)
Acceptance criteria
[ ] Every /v1/accounts/{id} handler checks the caller is an owner
or an authorized delegate of {id}, in the service layer
[ ] The check runs server-side on every request; client-supplied
roles or customer IDs in the body are ignored
[ ] Denied requests return 404 (no existence leak) and write an
audit event: caller, account id, decision, correlation id
[ ] Unit tests: own account ok, other customer denied, unknown id
denied, missing claims denied (fail closed)
Each line is testable, and the last one turns the fix into a regression test (L59). That's the difference between "we covered the Top 10" and "we can show the control works".
🧠 Extra takeaways
- Top 10 for awareness, Proactive Controls and Cheat Sheets for building, ASVS for verifying, WSTG for testing.
- ASVS has three levels; Level 2 is the usual target for apps handling financial data.
- Always cite the ASVS version with a requirement ID; numbering changed in 5.0.0.
- Turn requirements into acceptance criteria and tests, not just ticket labels.
CWE: the stable IDs behind every category
Top 10 category numbers change every few years. CWE IDs don't. If you tag findings with CWEs, you can re-map them to any edition, any list (Top 10, API Top 10, CWE Top 25), and any compliance framework without re-triaging.
CWE, CVE and CVSS: three different things
CWE-89 "SQL Injection" a TYPE of weakness
│ (the recipe for a bug)
│ appears in a specific product as
▼
CVE-2023-34362 one specific VULNERABILITY
(MOVEit Transfer SQL injection) in one product version
│
│ scored with
▼
CVSS 9.8 (Critical) how SEVERE that CVE is
in general (not to you,
see L02's deep dive)
Your own code's bugs usually get a CWE but never a CVE. CVEs are for published vulnerabilities in products and libraries, which is where SCA tools (L54) look.
Where CWEs show up in your tools
Static analysis rules carry CWE and OWASP tags in their metadata. A Semgrep finding, as JSON, looks roughly like this (trimmed; a real rule ID and message will differ):
{
"check_id": "java.jdbc.sqli.string-concat-query",
"path": "reports-svc/src/main/java/ReportDao.java",
"start": {"line": 42},
"extra": {
"severity": "ERROR",
"metadata": {
"cwe": ["CWE-89: Improper Neutralization of Special
Elements used in an SQL Command"],
"owasp": ["A03:2021 - Injection"]
}
}
}
Notice the owasp tag says 2021. Rule packs, scanners and dashboards update their OWASP labels
on their own schedules, so you'll see mixed editions for a while. Read the CWE and map it yourself.
Worked example: one table, both editions
| CWE | Name (short) | 2021 | 2025 |
|---|---|---|---|
| CWE-639 | Authorization bypass through user-controlled key (IDOR) | A01 | A01 |
| CWE-352 | Cross-site request forgery | A01 | A01 |
| CWE-918 | Server-side request forgery | A10 | A01 |
| CWE-89 | SQL injection | A03 | A05 |
| CWE-79 | Cross-site scripting | A03 | A05 |
| CWE-327 | Broken or risky crypto algorithm | A02 | A04 |
| CWE-1104 | Use of unmaintained third-party components | A06 | A03 |
| CWE-502 | Deserialization of untrusted data | A08 | A08 |
| CWE-755 | Improper handling of exceptional conditions | no prominent home | A10 |
A few surprises worth noticing: CSRF counts as access control (the attacker makes your browser do something it shouldn't), and XSS counts as injection (it had its own category up to the 2017 edition). Check OWASP's mapping pages for any CWE not listed here; mappings get small edits between drafts and the final edition.
The CWE Top 25: a sibling list
MITRE and CISA publish the CWE Top 25 Most Dangerous Software Weaknesses every year, ranked from CVE data rather than from application testing. In the 2024 edition, the top three were CWE-79 (XSS), CWE-787 (out-of-bounds write) and CWE-89 (SQL injection). Memory-safety bugs like CWE-787 rank high there because the list covers C and C++ products too, not just web apps. Same weaknesses, different lens.
🧠 Extra takeaways
- CWE is a weakness type, CVE is one product's vulnerability, CVSS is that CVE's generic severity.
- Tag findings with CWEs; category numbers change between editions, CWE IDs don't.
- Scanner OWASP labels often lag the newest edition; trust the CWE.
- The CWE Top 25 ranks weaknesses from CVE data and includes non-web, memory-safety bugs.
The quiz for this lesson and the Tests section need JavaScript.