The OWASP Top 10 is the single most important guide to web application security. It distills the ten most critical risks that developers, operators and security teams need to understand before attackers exploit them. Since early 2026 there is a new edition: the OWASP Top 10:2025. It is officially final, and OWASP now marks the previous 2021 edition as superseded.
This article brings you up to date. We explain all ten categories of the 2025 edition with a clear description, a concrete code example and a fix, edition by edition and backed by the official figures from owasp.org. In a dedicated section we also show exactly what changed from 2021 to 2025: which category was renamed, moved, merged or newly added.
If you want to go deeper on a single weakness, each category links to a focused follow-up article. That way this piece works both as an overview and as a practical starting point. Do not hand attackers the low-hanging fruit.
What is the OWASP Top 10?
The OWASP Top 10 is a standard document from the Open Web Application Security Project (OWASP), a nonprofit community that maintains free security resources. The list names the ten most critical security risks for web applications and is refreshed roughly every four years based on real-world data. It is not a complete security catalogue but an awareness document: it points teams at the most common and dangerous weaknesses and offers proven countermeasures.
For the 2025 edition, OWASP analysed around 175,000 records from more than 2.8 million applications and examined 589 distinct weakness classes (CWEs), of which 248 were mapped into the ten categories. The selection process is, in OWASP's words, "data-informed, but not blindly data-driven": eight of the ten categories come directly from the data, while two more are promoted through a community survey to surface emerging risks early.
One point matters for reading the numbers correctly: every figure belongs inseparably to its edition and its metric definition. An average incidence of 3.74 percent from the 2025 edition cannot be combined with a number from 2021, because the dataset, methodology and category boundaries all changed. We therefore label every figure with its edition.
Edition status: 2025 is final, 2021 is superseded
The OWASP Top 10:2025 is the eighth installment of the list and officially final. This is documented in OWASP's official GitHub repository, whose README marks the edition as "RELEASED" and "Final" and labels the 2021 edition as "SUPERSEDED". The project page on owasp.org confirms this too, naming the 2025 edition as the most current released version and 2021 as the previous version.
OWASP does not document an exact release date on its own website. According to secondary sources, a release candidate was presented at the Global AppSec Conference on 6 November 2025, and the final version was published in early 2026. Those dates do not come from OWASP itself but from third parties, which is why we explicitly flag them as "according to secondary sources". What is certain: as of now, 2025 is the authoritative, current edition.
A practical note: there is no official German OWASP translation of the 2025 edition yet, only English and Japanese. The English category names are therefore the binding reference. We use them throughout.
What changed from 2021 to 2025
On balance, OWASP describes the 2025 edition as having two new categories and one consolidation. The new entries are Software Supply Chain Failures and Mishandling of Exceptional Conditions. The consolidation is Server-Side Request Forgery (SSRF), the former standalone A10:2021 category, which is now folded into Broken Access Control. The table below shows, for each position, which name sits there in 2025 and what changed relative to 2021.
| Rank | 2021 | 2025 | Change |
|---|---|---|---|
| A01 | Broken Access Control | Broken Access Control | unchanged at number 1, now absorbs SSRF (formerly A10:2021) |
| A02 | Cryptographic Failures | Security Misconfiguration | Security Misconfiguration rises from rank 5 to rank 2 |
| A03 | Injection | Software Supply Chain Failures | new category, an expansion of "Vulnerable and Outdated Components" (A06:2021) |
| A04 | Insecure Design | Cryptographic Failures | Cryptographic Failures drops from rank 2 to rank 4 |
| A05 | Security Misconfiguration | Injection | Injection drops from rank 3 to rank 5 |
| A06 | Vulnerable and Outdated Components | Insecure Design | Insecure Design drops from rank 4 to rank 6 |
| A07 | Identification and Authentication Failures | Authentication Failures | same position, renamed (shortened) |
| A08 | Software and Data Integrity Failures | Software or Data Integrity Failures | same position, minor rename ("and" to "or") |
| A09 | Security Logging and Monitoring Failures | Security Logging and Alerting Failures | same position, renamed ("Monitoring" to "Alerting") |
| A10 | Server-Side Request Forgery (SSRF) | Mishandling of Exceptional Conditions | SSRF is removed as its own category and folded into A01, A10:2025 is brand new |
How to read the table correctly: the rows are not direct successors. Only for A01, A07, A08 and A09 does the same category sit at the same rank in both editions. The other rows merely show which category name occupies which rank number. Security Misconfiguration, for instance, climbed from rank 5 to rank 2, while Cryptographic Failures and Injection moved down.
The most important substantive points in plain terms:
- New, A03:2025 Software Supply Chain Failures: OWASP significantly expanded the former "Vulnerable and Outdated Components" category. It is no longer only about known vulnerabilities in libraries, but about the entire supply chain: dependencies, build systems and distribution infrastructure. In the community survey, 50 percent of respondents ranked this risk number one.
- New, A10:2025 Mishandling of Exceptional Conditions: a brand new category with 24 CWEs. It covers improper error handling, logical errors and "failing open", meaning a system that opens up insecurely when something goes wrong.
- Consolidated, SSRF: Back in 2021, OWASP predicted that the small SSRF category might later fold into a larger one. That is exactly what happened in 2025: SSRF is now part of Broken Access Control.
The rest of this article walks through all ten categories of the 2025 edition in order.
A01:2025 Broken Access Control
Description
Broken access control occurs when an application fails to enforce what a user is allowed to do. Unauthorised users can then access or modify resources that should be off limits, leading to data theft, unauthorised actions or exposure of confidential information. Common causes are missing server-side permission checks, reliance on client-side controls, and functionality exposed directly through manipulable URLs.
In the 2025 edition, Broken Access Control remains at number 1, with 40 mapped CWEs (the maximum allowed) and an average incidence of 3.74 percent in the 2025 dataset. According to OWASP, at least one tested application reached full coverage of this category. The notable change is that Server-Side Request Forgery (SSRF, formerly A10:2021) now belongs here. Defining weakness classes include CWE-200 (exposure of sensitive information), CWE-352 (Cross-Site Request Forgery) and CWE-918 (SSRF).
Example
Consider an application where users access their profile at /user/profile/123. If the application does not verify that the requesting user actually owns the profile, an attacker can simply change the URL to /user/profile/124 and view someone else's data. This is an Insecure Direct Object Reference (IDOR), one of the most common forms of broken access control.
# Flask example without access control
@app.route('/user/profile/<int:user_id>')
def user_profile(user_id):
user = users.get(user_id)
if user:
return jsonify(user)
return "User not found", 404
This vulnerable snippet never checks whether the requesting user is allowed to see the requested data. For how IDOR attacks work in detail and how to test for them systematically, see our article on Broken Access Control and IDOR.
Fix
# Flask example with access control
@app.route('/user/profile/<int:user_id>')
def user_profile(user_id):
logged_in_user_id = session.get('user_id')
if logged_in_user_id != user_id:
return "Forbidden", 403
user = users.get(user_id)
if user:
return jsonify(user)
return "User not found", 404
The secure version checks server-side that the authenticated user's ID matches the requested profile ID and denies access otherwise. The core rule: deny by default and enforce every permission check on the server, never in the browser alone.
Because SSRF now lives in this category, the following situation belongs here too. An application fetches a user-supplied URL, for example to load an image. Without restrictions, an attacker can supply an internal address and reach non-public services.
# Safe URL validation against SSRF (allowlist)
import requests
from urllib.parse import urlparse
ALLOWED_DOMAINS = ['example.com']
def is_allowed_url(url):
parsed_url = urlparse(url)
return parsed_url.hostname in ALLOWED_DOMAINS
def fetch_image(url):
if not is_allowed_url(url):
raise ValueError("URL is not allowed")
response = requests.get(url)
if response.status_code == 200:
with open('image.jpg', 'wb') as f:
f.write(response.content)
An allowlist of permitted targets is clearly preferable to a deny list, since attackers have extensive bypass lists for deny rules.
In API environments, the same authorization failures carry their own names: Broken Object Level Authorization (BOLA) describes missing object-level checks, and Broken Function Level Authorization (BFLA) missing function-level checks on individual endpoints. For how to secure these API authorization patterns specifically, see our article on API security and the OWASP Top 10.
Real-world case: In the Capital One breach (2019), the attacker used a Server-Side Request Forgery to reach the AWS cloud metadata service through a misconfigured web application firewall and steal temporary access credentials. According to the US Department of Justice indictment, this exposed data on roughly 106 million customers in the US and Canada. The case illustrates why SSRF is folded into A01 as an access-control problem in the 2025 edition. Large-scale scraping such as the Facebook incident (2021, roughly 533 million records per media reports) further shows how missing access and rate limits can expose data en masse.
A02:2025 Security Misconfiguration
Description
A security misconfiguration arises when an application or its environment is not set up securely: default passwords stay active, unnecessary services are exposed, error messages leak internal details, or hardening steps are missing. Such flaws are widespread and often easy to exploit because they require no sophisticated attack techniques.
In the 2025 edition, Security Misconfiguration rose from rank 5 (2021) to rank 2, because misconfigurations are more prevalent in the current data. The category covers 16 CWEs with an average incidence of 3.00 percent in the 2025 dataset. Defining weaknesses include CWE-16 (configuration) and CWE-611 (XML External Entities, XXE).
Example
A classic example is a web server that allows directory listing. If sensitive files sit in those directories, they become visible to anyone. In an Apache configuration, the risky setting looks like this:
<Directory "/var/www/html">
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
With Options Indexes, the contents of any directory under /var/www/html can be listed.
Fix
<Directory "/var/www/html">
Options -Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
The Options -Indexes directive disables directory listing. A solid hardening baseline also includes changing default credentials, disabling unused features and ports, using informative but non-revealing error messages, and applying a repeatable, documented hardening process across all environments.
A03:2025 Software Supply Chain Failures
Description
Software Supply Chain Failures is one of the two new categories in the 2025 edition. It substantially expands the former "Vulnerable and Outdated Components" (A06:2021). It is no longer only about known vulnerabilities in bundled libraries, but about the entire software supply chain: dependencies, build systems, package registries and distribution infrastructure. A tampered package, a compromised build server or a hijacked developer account can push malicious code into thousands of downstream applications.
OWASP grounds the category historically: it first appeared in 2013 as "Using Components with Known Vulnerabilities" and has grown in scope ever since. In the 2025 community survey, 50 percent of respondents ranked this risk number one. In the data, the category covers 6 CWEs and just 11 mapped CVEs, but with 5.72 percent it has the highest average incidence of any category in the 2025 dataset (the OWASP intro prose states 5.19 percent; 5.72 percent is the value from the score table).
Example
A common problem is pulling in dependencies loosely, without a fixed version and without integrity checks. If an application resolves packages at build time to any compatible version, a compromised or substituted version can slip in unnoticed:
{
"dependencies": {
"left-pad": "*",
"some-utils": "^1.0.0"
}
}
The wildcard * and the caret range ^ allow a new, unvetted version to be installed on the next build automatically. Without a lockfile carrying integrity hashes, there is no guarantee that everyone builds the exact same, verified state.
Fix
Pin dependencies to fixed versions and commit a lockfile that records a cryptographic integrity hash per package:
{
"name": "some-utils",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/some-utils/-/some-utils-1.0.3.tgz",
"integrity": "sha512-0Xa1b2C3..."
}
A robust supply-chain defence also includes a Software Bill of Materials (SBOM), automated scanning for known vulnerabilities in the CI/CD pipeline, signed artefacts and least-privilege build systems. For how lockfiles differ across npm, Yarn and pnpm and why they are central to reproducible builds, see our article on lockfiles.
To track known vulnerabilities in bundled components systematically, our CVE guide helps.
Real-world case: In the Equifax breach (2017), attackers got in through a known but unpatched flaw in the Apache Struts web framework (CVE-2017-5638) that had been public for months. According to the US Federal Trade Commission, roughly 147 million people were affected. The case is a textbook example of the core A03 risk: a vulnerable, outdated component in the supply chain that was not updated in time.
A04:2025 Cryptographic Failures
Description
Cryptographic failures occur when applications use encryption incorrectly or inadequately. Sensitive data such as passwords, personal information or financial records must be protected both in transit and at rest. Typical mistakes are outdated algorithms, missing transport encryption, poor key management and home-grown crypto without expert review.
In the 2025 edition, Cryptographic Failures dropped from rank 2 (2021) to rank 4. The category covers 32 CWEs with an average incidence of 3.80 percent in the 2025 dataset. Defining weaknesses include CWE-327 (broken or risky crypto algorithm), CWE-331 (insufficient entropy) and CWE-338 (cryptographically weak pseudo-random number generator).
Example
A frequent mistake is storing passwords with a weak hashing algorithm such as MD5. Such hashes can be reversed quickly using precomputed tables (rainbow tables).
# Weak MD5 hashing (insecure)
import hashlib
def hash_password(password):
return hashlib.md5(password.encode()).hexdigest()
MD5 is considered insecure because it is vulnerable to collisions and precomputed attacks, and it computes far too fast.
Fix
# Strong hashing with bcrypt
import bcrypt
def hash_password(password):
return bcrypt.hashpw(password.encode(), bcrypt.gensalt())
For passwords, use dedicated, deliberately slow algorithms such as bcrypt, scrypt or Argon2, which salt automatically and resist brute-force attacks. For data in transit, correctly configured TLS is mandatory. We cover the fundamentals in our article on HTTPS.
A05:2025 Injection
Description
Injection flaws arise when an application passes untrusted input unchecked into an interpreter, such as a SQL query, an HTML context or a system command. Attackers can then inject their own commands to read or modify data, or take over the system. The category includes SQL injection (less frequent but high impact) and Cross-Site Scripting (very common, usually lower individual impact), among others.
In the 2025 edition, Injection dropped from rank 3 (2021) to rank 5, yet with 62,445 mapped CVEs it remains the most CVE-heavy category of all. It covers 37 CWEs with an average incidence of 3.08 percent in the 2025 dataset. According to OWASP, Cross-Site Scripting accounts for more than 30,000 CVEs and SQL injection for more than 14,000 CVEs.
Example
If an application builds its SQL query by concatenating user input, an attacker can alter the query logic:
# SQLite with direct user input in the query (insecure)
import sqlite3
def search_items(keyword):
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
query = f"SELECT * FROM items WHERE name LIKE '{keyword}'"
cursor.execute(query)
return cursor.fetchall()
# Example call with an injected condition
items = search_items("value' OR '1'='1")
With the input value' OR '1'='1, the condition is always true, so the query returns every record. For how these attacks work in detail, see our article on SQL injection basics.
Fix
# SQLite with a parameterised query (secure)
import sqlite3
def search_items(keyword):
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
query = "SELECT * FROM items WHERE name LIKE ?"
cursor.execute(query, (f"%{keyword}%",))
return cursor.fetchall()
Parameterised queries cleanly separate code from data: the input is treated as a plain value and can no longer change the query structure. Other injection contexts each have their own defences.
For HTML output, context-aware escaping prevents Cross-Site Scripting.
For system commands, avoiding shell calls with user input prevents Remote Code Execution.
For file paths, strict validation prevents Local and Remote File Inclusion.
A06:2025 Insecure Design
Description
Insecure design refers to security flaws that are baked into an application's concept rather than introduced during coding. When threats are not thought through, business rules are not enforced server-side, or abuse scenarios are ignored, even clean code cannot save the design. Insecure design cannot be fixed by patching later, only by a better underlying concept.
In the 2025 edition, Insecure Design dropped from rank 4 (2021) to rank 6, as Security Misconfiguration and Software Supply Chain Failures leapfrogged it. The category covers 39 CWEs with an average incidence of 1.86 percent in the 2025 dataset, and it emphasises threat modelling and secure design patterns.
Example
A typical design flaw is a critical business function without server-side rule enforcement. Take a transfer function that relies solely on a limit checked in the browser:
# Insecure design: no server-side check of the business rule
@app.route('/transfer', methods=['POST'])
def transfer():
amount = float(request.form['amount'])
# The daily limit is only checked in the frontend, not here
execute_transfer(current_user, request.form['to'], amount)
return "Transfer done"
Because the limit is only checked in the frontend, an attacker can send the request straight to the server and transfer arbitrary amounts. The problem is not a single line of code but the design: the security rule was placed in the wrong location.
Fix
# Secure design: enforce the business rule server-side
DAILY_LIMIT = 10000
@app.route('/transfer', methods=['POST'])
def transfer():
amount = float(request.form['amount'])
if amount <= 0 or spent_today(current_user) + amount > DAILY_LIMIT:
return "Transfer denied", 403
execute_transfer(current_user, request.form['to'], amount)
return "Transfer done"
Secure design means modelling threats early, always enforcing business rules server-side, and planning for abuse from the start (rate limits, plausibility checks, clear trust boundaries). A proven guiding principle is Zero Trust architecture, which trusts no one implicitly.
A07:2025 Authentication Failures
Description
Authentication Failures (called "Identification and Authentication Failures" in 2021) covers all weaknesses that let attackers defeat identity verification: weak password rules, insecure session management, missing protection against automated guessing (credential stuffing, brute force), and insecure storage of credentials. OWASP shortened the name in 2025 to better reflect the 36 CWEs in this category.
The category stays at rank 7, with 36 CWEs and an average incidence of 2.92 percent in the 2025 dataset. Defining weaknesses include CWE-287 (improper authentication) and CWE-384 (session fixation).
Example
Weak authentication often shows up as two mistakes at once: insecure password hashing and predictable session identifiers.
# Insecure password storage and session management
import hashlib
import random
import string
def hash_password(password):
return hashlib.md5(password.encode()).hexdigest() # weak hashing
def generate_session_id():
return ''.join(random.choices(string.ascii_letters + string.digits, k=8)) # predictable
MD5 is too weak for passwords, and a short session ID generated with a non-cryptographic random source can be guessed or brute-forced.
Fix
# Secure password storage and session management
import bcrypt
import secrets
def hash_password(password):
return bcrypt.hashpw(password.encode(), bcrypt.gensalt()) # strong hashing
def generate_session_id():
return secrets.token_urlsafe(16) # cryptographically secure
bcrypt protects the passwords, and the secrets module produces unpredictable session identifiers. The biggest gain, however, comes from a second factor. For how to use it correctly, see our article on multi-factor authentication.
Even more resistant to phishing are passkeys based on the FIDO2 standard, which dispense with a reusable password altogether.
A08:2025 Software or Data Integrity Failures
Description
Software or data integrity failures occur when systems accept updates, critical data or deployment steps without verifying their authenticity and integrity. If software updates are installed without signature checks or untrusted data is deserialised, attackers can inject malicious code. The name changed slightly in 2025 from "and" to "or", and the category stays at rank 8.
It focuses on trust boundaries at a lower level than the supply-chain category A03. In the 2025 edition it covers 14 CWEs with an average incidence of 2.75 percent in the 2025 dataset. Defining weaknesses include CWE-502 (deserialisation of untrusted data), CWE-494 (download of code without integrity check) and CWE-829 (inclusion of functionality from an untrusted source).
Example
An application downloads and runs an update without verifying the file:
# Insecure update process without an integrity check
import requests
def download_update(url):
response = requests.get(url)
with open('update.zip', 'wb') as f:
f.write(response.content)
# no integrity check
Anyone who intercepts the download or compromises the server can substitute a malicious version.
Fix
# Secure update process with an integrity check
import requests
import hashlib
def verify_file_integrity(file_path, expected_hash):
sha256_hash = hashlib.sha256()
with open(file_path, 'rb') as f:
for chunk in iter(lambda: f.read(4096), b""):
sha256_hash.update(chunk)
return sha256_hash.hexdigest() == expected_hash
def download_update(url, expected_hash):
response = requests.get(url)
with open('update.zip', 'wb') as f:
f.write(response.content)
if not verify_file_integrity('update.zip', expected_hash):
raise ValueError("File integrity check failed")
The application compares the hash of the downloaded file against an expected SHA-256 value and rejects tampered downloads. In practice, signatures and trusted distribution channels come on top. Because integrity failures are closely tied to dependencies, our CVE guide is useful here too.
Equally important for verifiable, unchanged dependency states are reproducible builds via lockfiles.
Real-world case: In the SolarWinds incident (2020), attackers used the compromised build pipeline of the Orion software to slip the SUNBURST malware into a regularly signed update. According to the US agency CISA, roughly 18,000 organisations downloaded the tampered version. Because the update was not verified for the integrity of its origin despite a valid signature, the case is a model example of software or data integrity failures.
A09:2025 Security Logging and Alerting Failures
Description
Without sufficient logging and, as the 2025 edition stresses in its new name, without effective alerting, attacks often go undetected for a long time. OWASP renamed the category from "Monitoring" to "Alerting" in 2025 to make the point clear: logging without alerting is of minimal value for spotting incidents. When records of login attempts, access events and critical changes are missing, attacks can neither be detected nor investigated forensically.
The category stays at rank 9, with 5 CWEs and an average incidence of 3.91 percent in the 2025 dataset. As in 2021, it comes from the community survey.
Example
An authentication function that does not log failed login attempts leaves no trace to detect brute-force attacks:
# Without logging of failed logins
def authenticate_user(username, password):
user = get_user_from_database(username)
if user and user.verify_password(password):
return "Authentication successful"
return "Authentication failed"
Fix
# With logging of failed logins
import logging
logging.basicConfig(filename='auth.log', level=logging.INFO)
def authenticate_user(username, password):
user = get_user_from_database(username)
if user and user.verify_password(password):
logging.info(f"User {username} authenticated successfully")
return "Authentication successful"
logging.warning(f"Failed login attempt for user {username}")
return "Authentication failed"
The secure version logs both success and failure. The decisive second step is turning those logs into automatic alerts on suspicious patterns, such as many failures in a short window. For how organisations set up detection and response, our article on MDR, MSSP, EDR, XDR and NDR provides context. Also protect the logs themselves against tampering and deletion.
A10:2025 Mishandling of Exceptional Conditions
Description
Mishandling of Exceptional Conditions is the second brand new category in the 2025 edition. It bundles failures in dealing with abnormal conditions: sloppy exception handling, logical errors, revealing error messages and, above all, "failing open", meaning a system that opens up insecurely when something goes wrong. OWASP previously grouped these weaknesses under the overly broad heading of "poor code quality" and gave them a dedicated, more precise category in 2025.
The category covers 24 CWEs with an average incidence of 2.95 percent in the 2025 dataset. Defining weaknesses include CWE-209 (information exposure through error messages), CWE-476 (NULL pointer dereference) and CWE-636 (not failing securely, "failing open").
Example
The most dangerous case is an access decision that resolves in the user's favour on error. If the permission check throws an exception and the code catches it too generously, access may be granted instead of denied:
# Failing open: an error wrongly grants access
def is_authorized(user, resource):
try:
return check_permissions(user, resource)
except Exception:
return True # wrong: opens up on any error
On top of that, unfiltered error messages often reveal internal details such as stack traces or database paths that help an attacker.
Fix
# Failing closed: an error denies access
import logging
def is_authorized(user, resource):
try:
return check_permissions(user, resource)
except Exception as e:
logging.error(f"Permission check failed: {e}")
return False # safe: denies when in doubt
Secure systems fail into a safe state (fail closed): on error, access is denied, not granted. Catch exceptions deliberately, log the error internally, and return only generic messages without technical details to the outside.
Related OWASP projects
The Top 10 is only the entry point. OWASP and adjacent initiatives offer further resources that complement the web focus:
- OWASP API Security Top 10: a separate ranking specifically for API risks, deepening topics such as Broken Object Level Authorization. Details in our article on API security and the OWASP Top 10.
- OWASP Top 10 for LLM Applications: a separate list for generative-AI risks such as prompt injection. Our article on the basics of prompt injection is a good start.
- OWASP Cheat Sheet Series: concise, practical implementation guides for many of the topics above.
- CWE Top 25 (MITRE): a related but broader list. Where the OWASP Top 10 focuses on web applications, the CWE Top 25 covers the most dangerous weakness classes across all kinds of software.
Tools for implementing the OWASP Top 10
Theory alone secures nothing. Only the right tools in the development process make the OWASP Top 10 practically effective. A sensible setup combines static analysis, dynamic testing and dependency checking:
- Static analysis (SAST): tools such as SonarQube, Semgrep, CodeQL or, for Python, Bandit find risky patterns directly in source code, such as unsafe function calls or missing validation.
- Dynamic testing (DAST): OWASP ZAP (Zed Attack Proxy) probes the running application for weaknesses such as Cross-Site Scripting or insecure redirects and integrates into CI/CD pipelines.
- Dependency scanning (SCA): OWASP Dependency-Check and similar tools flag known vulnerabilities in bundled libraries, which is especially important for A03 and A08.
- Pipeline integration: in Jenkins, GitLab CI or GitHub Actions these checks can be automated so that weaknesses surface early and repeatably.
FAQ
What is the OWASP Top 10?
The OWASP Top 10 is a standard document from the Open Web Application Security Project that names the ten most critical security risks for web applications. It is not a complete security catalogue but an awareness document, refreshed roughly every four years based on real-world data. The authoritative version right now is the 2025 edition.
What changed in the OWASP Top 10 2025?
The 2025 edition introduces two new categories and one consolidation: the new entries are Software Supply Chain Failures (A03) and Mishandling of Exceptional Conditions (A10). Server-Side Request Forgery is removed as a standalone category and folded into Broken Access Control. On top of that, Security Misconfiguration rises from rank 5 to rank 2, and several categories were renamed.
Is the OWASP Top 10 2021 still current?
No. OWASP marks the 2021 edition as "SUPERSEDED" in its official GitHub repository and the 2025 edition as "RELEASED" and "Final". For new projects and assessments, you should align with the 2025 edition.
What is the most common vulnerability according to OWASP?
Broken Access Control remains at number 1 in the ranking, with an average incidence of 3.74 percent in the 2025 dataset. The highest average incidence of any category, however, belongs to Software Supply Chain Failures at 5.72 percent. The ranking results from several factors, not from incidence alone.
How do I apply the OWASP Top 10 in practice?
Combine static analysis (SAST), dynamic testing (DAST) and dependency scanning (SCA), and integrate these checks into your CI/CD pipeline. Tools such as OWASP ZAP, OWASP Dependency-Check, Semgrep or Bandit help you cover the individual categories concretely. On top of that come secure design, vetted dependencies and regular penetration testing.
Conclusion
The OWASP Top 10 is an indispensable foundation for secure web applications, and the final 2025 edition has shifted the picture noticeably: Security Misconfiguration moves up, Software Supply Chain Failures is recognised as a standalone major risk, Mishandling of Exceptional Conditions is added, and SSRF folds into Broken Access Control. Understanding these shifts helps you prioritise your defences correctly.
Keep in mind that the list captures only the most common risks, not all of them. Absolute security does not exist, but risk can be reduced sharply: through secure design, vetted dependencies, clean error handling, effective logging with alerting, and regular testing such as penetration tests or bug bounty programs. Use the linked deep-dive articles to translate each category into practice. Doing nothing is not an option, because otherwise a successful attack is only a matter of time.