The OWASP Top 10 for Web Apps
On this page
- The Consensus Map of What Breaks
- A01: Broken Access Control
- A02: Security Misconfiguration
- A03: Software Supply Chain Failures
- A04: Cryptographic Failures
- A05: Injection
- A06: Insecure Design
- A07: Authentication Failures
- A08: Software or Data Integrity Failures
- A09: Security Logging and Alerting Failures
- A10: Mishandling of Exceptional Conditions
- Why a Risk List Beats a Bug List
- How the List Evolves and How to Use It
The Consensus Map of What Breaks#
The OWASP Top 10 is a community-built list of the most critical web application security risks, refreshed every few years (the 2025 edition is the current one, replacing 2021; the numbering below is the 2025 list). It is not a scanner checklist or a ranking of individual bugs; each entry is a broad risk category that contains many specific flaws. Its real value is as shared vocabulary: your team, your auditors and your pentest reports all speak in these terms, so knowing them turns "we did some security work" into a structured conversation about coverage.
Treat it as a map. For each category, ask "how does this apply to our stack, and what is our control?" The entries you cannot answer confidently become your roadmap.
A01: Broken Access Control#
The most frequently found category. The application authenticates users but fails to authorize individual actions: a user reads /account/42 that belongs to someone else, a normal user reaches an admin endpoint, or a GET request performs a delete. The fix is centralised, deny-by-default authorization checked on every request and scoped to the acting user, never trusting a client-supplied role or a hidden menu. The IDOR lesson covers the most common instance in detail.
The difference between the broken and the fixed version is small in code but total in effect:
# BROKEN: returns the record for any id, to anyone logged in
def get_invoice(invoice_id, user):
return db.invoices.find_one({"_id": invoice_id})
# FIXED: the query is scoped to the caller, so a non-owned id returns nothing
def get_invoice(invoice_id, user):
return db.invoices.find_one({"_id": invoice_id, "owner_id": user.id})
The broken version checks authentication (the user is logged in) but never authorization (the invoice is theirs). Scoping the lookup to the owner makes cross-user access impossible rather than merely discouraged.
In the 2025 edition this category also absorbs Server-Side Request Forgery (SSRF), which was its own entry (A10) in 2021: a server tricked into fetching attacker-chosen URLs becomes a proxy into its own internal network and cloud metadata service. It has its own SSRF lesson covering detection and defence. Cross-site request forgery (CSRF) is mapped here too.
A02: Security Misconfiguration#
Up from fifth place in 2021. Default credentials still active, verbose error pages leaking stack traces and versions, unnecessary features and ports enabled, permissive CORS wildcards, unpatched default installs. The fix is hardening: disable what you do not use, remove defaults, and scan configurations. The security headers lesson covers one important slice.
A03: Software Supply Chain Failures#
New in 2025, expanding 2021's "Vulnerable and Outdated Components". It still covers running a framework, library, runtime or OS with a known vulnerability, the "we never updated that dependency" class, but now also compromises anywhere in the process of building, distributing or updating software: a hijacked package, a malicious maintainer, a poisoned build pipeline. The fix is knowing your inventory (a software bill of materials, including transitive dependencies), monitoring advisories, taking components only from trusted sources, locking down repositories and CI/CD with MFA and least privilege, and a patch cadence that treats dependency health as ongoing debt, covered in supply chain security.
A04: Cryptographic Failures#
Sensitive data left unprotected in transit or at rest, or protected badly: missing TLS, weak or home-grown crypto, hardcoded keys, passwords stored reversibly. The fix is the whole terrain of the encryption and hashing lessons: TLS 1.2+ everywhere, vetted algorithms, salted slow password hashes, and disciplined key management.
A05: Injection#
Untrusted input interpreted as code: SQL injection, command injection, and XSS all live here. The unifying fix is to separate code from data: parameterized queries, argument lists instead of shell strings, and context-aware output encoding. Injection has slid down the list (first in 2017, third in 2021, fifth in 2025) largely because frameworks now escape by default; it remains dangerous precisely where developers step outside those defaults with raw queries and string-built commands.
A06: Insecure Design#
Added in the 2021 edition, shifting attention to flaws baked in at design time rather than coding mistakes: a business flow with no rate limiting by design, trust boundaries drawn too wide, missing threat modeling. You cannot patch your way out of a bad design; the fix is secure design reviews and structural controls before code is written.
A07: Authentication Failures#
(Called "Identification and Authentication Failures" in 2021.) Weak login, missing MFA, credential stuffing enabled by no rate limiting, session IDs exposed in URLs or never invalidated, insecure "remember me." The fix is the authentication concepts toolkit: MFA where it matters, strict session management, rate limiting, and proper password storage.
A08: Software or Data Integrity Failures#
Trusting code or data whose integrity was never verified: unsigned or unpinned updates and artifacts, insecure CI/CD pipelines, and deserialization of untrusted data. The fix is signed artifacts, pinned hashes, hardened pipelines, and never deserializing attacker-controlled input.
A09: Security Logging and Alerting Failures#
(Called "Security Logging and Monitoring Failures" in 2021; the new name stresses that logs nobody is alerted on do not help.) The breach you never detect because nothing was logged or nobody was watching. The fix is logging security-relevant events (logins, failures, privilege changes, high-value actions) with alerting wired up, so that incident response can actually begin. Logs must be tamper-resistant and retained long enough to investigate a slow breach.
A10: Mishandling of Exceptional Conditions#
New in 2025. Applications that fail to prevent, detect or respond safely to unusual situations: errors that leak stack traces or secrets, code that fails open (an exception in the permission check is caught and the request proceeds), half-finished transactions left in an inconsistent state, unchecked nulls and resource exhaustion. The fix is to catch errors where they occur and handle them deliberately, fail closed, roll back partial transactions completely, add limits and quotas so exceptional conditions are less likely in the first place, and use a consistent global error handler that logs the detail and shows the user a generic message.
Why a Risk List Beats a Bug List#
It is worth understanding why OWASP frames these as categories rather than specific vulnerabilities. A specific bug (say, one XSS on the search page) gets fixed and forgotten. A category (Injection) is a class of bug that recurs wherever the same mistake is possible, so a control that addresses the category (parameterize every query, encode every output) prevents the next instance you have not found yet. Security maturity is measured by category-level controls, not by the count of individual bugs closed. When a report says "we fixed the SQL injection," the better question is "what stops the next one," and the category framing is what forces that question.
The list is also risk-ordered by real-world data (frequency, exploitability, impact) gathered from many organisations, not by theoretical severity. That is why Broken Access Control sits at the top: it is both common and damaging. Spending effort in list order is a reasonable default when you have no other signal about where your own weaknesses lie.
How the List Evolves and How to Use It#
Categories change between editions as the industry learns. The 2021 edition consolidated older entries (XSS folded into Injection), promoted design and integrity as first-class concerns, and added SSRF by community vote. The 2025 edition folded SSRF into Broken Access Control, widened outdated components into Software Supply Chain Failures, moved Security Misconfiguration up to second, and added Mishandling of Exceptional Conditions. Do not memorise the numbers; understand the risks, because the shape of each problem outlives its rank.
A practical way to apply the list:
- Map each entry to your architecture. Write one line per category naming your control and where it lives. Blanks are findings.
- Turn it into tests. Access-control and injection failures are testable in CI: run the app as several roles against every route, and fuzz inputs with quote- and metacharacter-heavy payloads.
- Feed it into design and review. Use A06 (Insecure Design) and A03/A08 (supply chain and integrity) as prompts during design, and the whole list as a checklist during code review and before release.
- Know the siblings. There are companion Top 10 lists for APIs and mobile; if you ship those, read them too, because the web list does not cover object-level API authorization or mobile-specific storage risks well.
The Top 10 is not a compliance box to tick. It is the distilled experience of thousands of practitioners about where applications actually break, and its best use is as a recurring lens on your own system rather than a certificate to frame.
Check your understanding
4 quick questions on this lesson. Get them all right and the lesson is marked complete.