In short. The OWASP Top 10 2025, the first update since 2021, keeps broken access control at number one, moves security misconfiguration to second and adds two categories: software supply chain failures and mishandling of exceptional conditions. This guide takes each category from a penetration tester’s view: what it means, how it shows up in real applications and what fixes it.
The OWASP Top 10 is the most widely used list of web application security risks, and the 2025 edition, published in November 2025, is the first update since 2021. Broken access control stays at number one. Security misconfiguration rises to second. Two categories are new: software supply chain failures, which replaces the old “vulnerable and outdated components”, and mishandling of exceptional conditions. Server-side request forgery is no longer a category of its own and now sits under broken access control. This guide goes through the 2025 list from the point of view of a penetration tester: what each category means, how it shows up in real applications, and what fixes it.
What changed between 2021 and 2025
| 2025 | Category | Change from 2021 |
|---|---|---|
| A01 | Broken Access Control | Unchanged at #1; now also covers SSRF |
| A02 | Security Misconfiguration | Up from #5 |
| A03 | Software Supply Chain Failures | New; broadens “Vulnerable and Outdated Components” |
| A04 | Cryptographic Failures | Down from #2 |
| A05 | Injection | Down from #3 |
| A06 | Insecure Design | Down from #4 |
| A07 | Authentication Failures | Renamed from “Identification and Authentication Failures” |
| A08 | Software or Data Integrity Failures | Unchanged |
| A09 | Security Logging and Alerting Failures | Renamed from “Logging and Monitoring Failures” |
| A10 | Mishandling of Exceptional Conditions | New |
The direction of travel is telling. The categories that moved up are about how applications are deployed, configured and assembled from other people’s code. The categories that moved down are the classic coding flaws that frameworks now largely prevent by default. That matches what we see: the SQL injection in a hand-written query is rarer than it was; the admin panel reachable because a default was never changed is not.
A01: Broken access control
Access control is the set of rules about who can do what. It fails when the application checks that you are logged in but not that you are allowed to see this record, call this function or act on this account. The commonest form is still the insecure direct object reference: change the ID in the URL or the API request and you are looking at someone else’s invoice. Others include privilege escalation through a parameter the front end hides but the back end trusts, and, now included here, server-side request forgery, where the application can be persuaded to make requests to internal systems on the attacker’s behalf.
In testing this is the category most likely to produce a critical finding, because it is invisible to scanners and depends entirely on business logic. The fix is a single, server-side authorisation check on every request, denying by default, with object-level checks that ask “does this user own this thing” rather than “is this user logged in”.
A02: Security misconfiguration
Everything around the code: default accounts, verbose error pages, directory listing, unnecessary features left enabled, cloud storage that is public, security headers missing, debug endpoints in production, permissive CORS. Misconfiguration moved up because modern applications have more surfaces to misconfigure: the framework, the container, the orchestration layer, the cloud services and the identity provider each have their own defaults.
We find this on almost every engagement in some form. On its own each item is usually low or medium severity; chained with something else it is often the step that turns a nuisance into a breach. The fix is a hardened, repeatable build with configuration held in code and reviewed, plus removal of anything not needed in production.
A03: Software supply chain failures
The new category covers the whole dependency chain: the libraries and frameworks you import, the packages they import in turn, the build tooling, the container base images and the update mechanisms that deliver all of them. The old category was about running outdated components; this one recognises that a component can be current and still compromised, and that the build pipeline is itself a target.
In testing we identify the components and versions an application uses and check them against known vulnerabilities, but the more valuable finding is usually structural: no software bill of materials, no process for acting on a vulnerable dependency, build servers with production credentials, or packages pulled from public registries without pinning or verification. The fix is knowing what you ship, pinning and verifying it, and having a way to update it quickly when you must.
A04: Cryptographic failures
Sensitive data transmitted or stored without adequate protection: passwords hashed with a fast algorithm or not at all, TLS misconfigured or optional, tokens that are predictable, keys hard-coded in the application or committed to a repository. The category has moved down because platforms now do most of this correctly out of the box, but it still appears wherever a developer has built their own instead.
The fix is to use the platform’s primitives: modern TLS everywhere, a slow adaptive hash for passwords, a proper secrets store for keys, and no custom cryptography.
A05: Injection
Injection occurs when user input is treated as code: SQL, NoSQL, operating system commands, LDAP, templates and, still, cross-site scripting. It has fallen from third to fifth because parameterised queries and templating engines that escape output by default have made the classic forms harder to introduce by accident. It has not gone away. We still find it in legacy code, in stored procedures built with string concatenation, in search features that assemble queries dynamically, and in reflected parameters that nobody thought were rendered.
The fix has not changed in twenty years: parameterise queries, validate input against what is expected, encode output for the context it is rendered in, and use a content security policy as a second line for cross-site scripting.
A06: Insecure design
Insecure design is a flaw in what the application is meant to do, not how it does it: a password reset that asks for information an attacker can find, a checkout that trusts a price sent by the browser, a workflow that can be replayed, a rate limit that does not exist. No amount of secure coding fixes a design that is wrong.
These findings come from understanding the business and abusing its assumptions, which is why a penetration test of an application should include the tester reading the documentation and asking what the application is for. The fix is threat modelling before the code is written and abuse cases alongside the use cases.
A07: Authentication failures
Weak or missing multi-factor authentication, credential stuffing left unthrottled, password rules that allow known-breached passwords, session tokens that do not rotate on login or expire on logout, and “remember me” implementations that never forget. The rename from “identification and authentication” simplifies the label; the content is the same.
We test authentication on every application and it remains one of the most productive areas. The fix is MFA for anything that matters, throttling and monitoring of failed logins, a check against breached-password lists, and session handling that follows the framework’s defaults rather than reinventing them.
A08: Software or data integrity failures
Trusting code or data without verifying it: deserialising objects from untrusted sources, auto-updating from a location that is not signed, CI/CD pipelines that will build and deploy whatever is pushed to them, plugins loaded from anywhere. This overlaps with supply chain failures but focuses on the integrity check that should exist and does not.
The fix is signatures and verification on anything the application loads or updates from, and treating the deployment pipeline as production infrastructure with the same access controls.
A09: Security logging and alerting failures
The rename from monitoring to alerting is deliberate. Logs that nobody reads are not a control. The failure is not knowing that an attack is happening: failed logins not recorded, high-value transactions not logged, logs held only on the server that was compromised, no alert when a user downloads the whole customer table.
A penetration test can tell you whether your logging works, because we generate exactly the events it should catch. If nobody noticed us, that is a finding. The fix is logging security-relevant events with enough context to investigate, shipping them somewhere the attacker cannot reach, and alerting on the handful of patterns that matter.
A10: Mishandling of exceptional conditions
The second new category covers what an application does when something goes wrong: an error path that fails open, an exception that leaks a stack trace with database details, a timeout that leaves a transaction half-complete, a race condition between two requests that lets a discount be used twice. These are logic and error-handling flaws rather than input flaws, and they are increasingly where the interesting findings are.
The fix is to fail closed, handle errors deliberately, keep detail out of what the user sees, and test the unhappy paths as thoroughly as the happy ones.
How we test against the OWASP Top 10
The OWASP Top 10 is an awareness list, not a testing methodology. A web application penetration test should cover every category on it and a great deal that is not: business logic, multi-step workflows, the APIs behind the front end, and the way the application interacts with the identity provider and the cloud services around it. We test with credentials for each role the application has, because the most serious access control findings can only be found from inside a valid session, and we map the application before we attack it so that coverage is deliberate rather than accidental.
Our web application penetration testing and API penetration testing pages describe scope and approach. Every engagement is scoped by an active tester, delivered by a named consultant, and reported within 5 working days with a retest included so that fixes are verified rather than assumed. The sample report shows what a finding looks like on the page.
Frequently asked questions
What is new in the OWASP Top 10 2025?
Two new categories: Software Supply Chain Failures (A03) and Mishandling of Exceptional Conditions (A10). Server-side request forgery has been folded into Broken Access Control. Security Misconfiguration has risen to second place. Two categories were renamed: Authentication Failures and Security Logging and Alerting Failures.
Is passing an OWASP Top 10 scan the same as being secure?
No. Automated scanners find some injection, misconfiguration and outdated-component issues. They do not find access control flaws, insecure design or business logic problems, which are where the serious findings are. The Top 10 itself says it is an awareness document.
How often should a web application be tested?
At least annually and after any significant release. Applications that change continuously benefit from testing tied to major releases rather than the calendar.
Should APIs be tested separately?
They should be tested deliberately, whether as part of the application test or on their own. Mobile and single-page applications push most of the logic into APIs, and an API that trusts the client is the commonest route past the controls the front end appears to enforce.