OWASP Top 10:2025 Web Application Security Risks
The current OWASP Top 10:2025 web application security risk categories with concrete mitigation guidance and code-level examples for each, grounded in the official OWASP release.
Introduction / Overview
The OWASP Top 10 is the standard, community-consensus awareness document for the most critical web application security risks, maintained by the Open Worldwide Application Security Project. The OWASP Top 10:2025 revision is the current release as of this writing and introduces two new categories relative to the 2021 edition - Software Supply Chain Failures and Mishandling of Exceptional Conditions - reflecting the industry's growing exposure to dependency-based attacks and the reality that unhandled error paths are a persistent, exploitable source of information disclosure and logic bypass.
This document walks through each of the ten categories in their official 2025 order, with mitigation guidance and minimal code examples per category. It should be read alongside Secure Coding Practices, which covers the underlying language-agnostic techniques (validation, encoding, least privilege) that address most of these categories simultaneously.
When to use this guidance: Threat-modeling a new feature, conducting a security review of existing code, prioritizing a security backlog, or educating a team on the current highest-impact risk categories for web applications.
Core Concepts
- Risk category, not vulnerability list: Each OWASP Top 10 entry is a class of risk (e.g., "Injection") encompassing many specific vulnerability types (SQL injection, command injection, template injection), not a single CVE or bug pattern.
- Ordered by prevalence and impact, not severity alone: The ranking reflects a combination of how often each category is found in tested applications and the typical business impact when exploited - a rare-but-catastrophic risk and a common-but-low-impact risk can both appear mid-list.
- Shift from injection to systemic risks: The 2025 ordering reflects a broader industry shift - access control and configuration issues (systemic, architecture-level) now rank above classic injection (a code-level defect), reflecting where real-world breaches are concentrated.
- Defense in depth across categories: Most real incidents involve chained failures across two or more of these categories (e.g., a misconfiguration exposing an endpoint that has an access control flaw, logged via a supply-chain-compromised logging library).
The OWASP Top 10:2025 Categories
A01:2025 - Broken Access Control
Access control enforces that a user can only act within their intended permissions. This category - the top risk for both the 2021 and 2025 editions - includes privilege escalation, insecure direct object references (IDOR), and (newly consolidated into this category for 2025) Server-Side Request Forgery (SSRF).
Mitigation:
@app.get("/invoices/{invoice_id}")
async def get_invoice(
invoice_id: int,
current_user: Annotated[User, Depends(get_current_user)],
invoice_service: Annotated[InvoiceService, Depends(get_invoice_service)],
):
invoice = await invoice_service.get(invoice_id)
if invoice is None or invoice.owner_id != current_user.id:
raise HTTPException(status_code=404) # 404, not 403 - avoid confirming existence
return invoice
- Enforce authorization checks server-side on every request, scoped to the authenticated principal - never rely on a client-supplied ID being sufficient proof of ownership.
- For SSRF specifically: validate and allowlist outbound destination hosts/schemes before the application makes any server-initiated request based on user input (webhooks, URL previews, image fetchers).
A02:2025 - Security Misconfiguration
Security Misconfiguration rose from #5 in 2021 to #2 in 2025, driven by increasingly complex cloud-native stacks (Kubernetes, managed services, IaC) where a single misconfigured default can expose an entire environment. Covers unnecessary features enabled, default credentials, verbose error messages, permissive CORS, and missing security headers.
Mitigation:
class Settings(BaseSettings):
debug: bool = False
cors_allowed_origins: list[str] = [] # explicit allowlist, never "*" with credentials
- Harden every layer of the stack (application framework, container runtime, cloud IAM, orchestrator) against its insecure defaults - see Docker Best Practices for the container-level equivalent.
- Automate configuration auditing (e.g.,
kube-bench, cloud security posture management tooling) as a recurring, not one-time, check.
A03:2025 - Software Supply Chain Failures
New for 2025. Covers compromised or malicious dependencies, unverified build pipelines, typosquatted packages, and unsigned artifacts - the class of risk behind incidents like the event-stream, xz-utils, and various dependency-confusion attacks.
Mitigation:
- name: Software composition analysis
run: pip-audit --strict --vulnerability-service osv
- name: Verify image signature before deploy
run: cosign verify --key cosign.pub myregistry.example.com/myapp:${{ github.sha }}
- Generate and retain an SBOM for every build (see Docker Best Practices).
- Pin dependency versions with lockfiles, verify package integrity hashes, and run SCA scanning on every pipeline execution (see CI/CD Patterns).
- Require signed commits (see Git Best Practices) and signed build artifacts so provenance is verifiable end-to-end.
A04:2025 - Cryptographic Failures
Covers weak or missing encryption in transit and at rest, use of broken/deprecated algorithms (MD5, SHA-1 for passwords, unpadded RSA), hardcoded keys, and improper certificate validation.
Mitigation:
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["argon2"], deprecated="auto")
hashed = pwd_context.hash(plaintext_password)
- Use vetted libraries (argon2/bcrypt for passwords, TLS 1.2+ with modern cipher suites for transport) - never implement cryptographic primitives directly (see Secure Coding Practices).
- Never disable certificate verification, even temporarily in "debug" code paths that can leak into production configuration.
A05:2025 - Injection
Includes SQL, NoSQL, OS command, LDAP, and template injection - any case where untrusted data is interpreted as code or query structure by a downstream interpreter. Fell from #3 to #5 in 2025, reflecting the effectiveness of widespread ORM/parameterized-query adoption, though it remains a top-tier risk.
Mitigation:
cursor.execute("SELECT * FROM users WHERE email = %s", (email,)) # parameterized
subprocess.run(["ping", "-c", "1", hostname], shell=False) # no shell=True with user input
- Always use parameterized queries/prepared statements or ORM query builders; never string-concatenate or f-string untrusted input into a query, shell command, or template.
- See Secure Coding Practices for the full pattern.
A06:2025 - Insecure Design
Represents architectural and threat-modeling failures - missing rate limiting on sensitive operations, business logic that assumes trust it should not, absence of abuse-case analysis during design. Distinct from an implementation bug: the design itself lacks a necessary security control.
Mitigation:
- Conduct threat modeling (e.g., STRIDE) during design for any feature handling money, PII, or privileged actions, before implementation begins.
- Apply rate limiting and anomaly detection to sensitive flows (password reset, MFA enrollment, payment) as a design requirement, not an afterthought.
- Reference SOLID Principles and Microservices Architecture for architectural practices that make secure design easier to reason about and review.
A07:2025 - Authentication Failures
Covers credential stuffing susceptibility, weak password policies, missing multi-factor authentication (MFA) on sensitive accounts, session fixation, and improperly implemented password recovery flows.
Mitigation:
class LoginRequest(BaseModel):
email: EmailStr
password: str = Field(min_length=8, max_length=128)
- Enforce MFA for privileged accounts and sensitive operations; use vetted session/token libraries with secure cookie flags (
HttpOnly,Secure,SameSite=Strict). - Apply progressive delays or account lockout with care (avoid enabling denial-of-service via lockout) combined with rate limiting on authentication endpoints.
A08:2025 - Software or Data Integrity Failures
Covers insecure deserialization, unsigned/unverified auto-update mechanisms, and CI/CD pipelines that allow unverified code or artifacts to be promoted to production.
Mitigation:
- Avoid native deserialization of untrusted data (Python
pickle, Java native serialization); prefer schema-validated formats (JSON via Pydantic, Protocol Buffers). - Verify integrity (checksums, signatures) of any auto-updated component or third-party artifact before use, and enforce it at the CI/CD gate (see CI/CD Patterns).
A09:2025 - Security Logging and Alerting Failures
Insufficient or absent logging of authentication events, access control failures, and high-value transactions delays breach detection - median time-to-detect a breach remains measured in weeks to months industry-wide when logging is inadequate.
Mitigation:
logger.warning("access_denied", extra={"user_id": user.id, "resource": resource_id, "action": "delete"})
- Log security-relevant events (authentication success/failure, access denials, privilege changes) with sufficient context to reconstruct an incident, while excluding sensitive data values (see Secure Coding Practices).
- Ensure logs are shipped to a system the attacker cannot trivially delete from the compromised host itself, and wire alerting thresholds for anomalous patterns (repeated auth failures, privilege escalation attempts).
A10:2025 - Mishandling of Exceptional Conditions
New for 2025. Covers error paths that fail open instead of fail closed, verbose stack traces or debug information leaked to clients, unhandled exceptions that bypass security checks further down a call chain, and inconsistent error handling across a distributed system.
Mitigation:
@app.exception_handler(Exception)
async def unhandled_exception_handler(request: Request, exc: Exception):
logger.exception("unhandled_error", extra={"path": request.url.path})
return JSONResponse(status_code=500, content={"detail": "Internal server error"}) # no stack trace to client
- Centralize exception handling (see FastAPI Best Practices) so every unhandled error returns a generic, safe response rather than leaking a stack trace, and defaults to a fail-closed state for security-relevant checks (e.g., an authorization check that errors should deny, not permit, access).
- Audit multi-step transactional flows for partial-failure states that could leave the system in an inconsistent, exploitable condition.
Best Practices Summary Table
| Category | Primary Code-Level Control | Primary Architectural Control |
|---|---|---|
| A01 Broken Access Control | Server-side authorization check per request | Centralized authorization middleware/policy engine |
| A02 Security Misconfiguration | Secure-by-default settings classes | Automated configuration auditing (IaC scanning) |
| A03 Software Supply Chain Failures | Lockfiles, integrity hashes | SBOM + signed artifacts + SCA gate in CI |
| A04 Cryptographic Failures | Vetted libraries (argon2, TLS) | Centralized secrets/key management |
| A05 Injection | Parameterized queries | Least-privilege database accounts |
| A06 Insecure Design | Rate limiting on sensitive endpoints | Threat modeling during design phase |
| A07 Authentication Failures | Strong session/token handling, MFA | Centralized identity provider |
| A08 Data Integrity Failures | Schema-validated deserialization | Signed CI/CD artifact provenance |
| A09 Logging and Alerting Failures | Structured security event logging | Centralized log aggregation + alerting |
| A10 Mishandling of Exceptional Conditions | Centralized exception handlers, fail-closed | Consistent error-handling policy across services |
Common Pitfalls & Anti-Patterns
Pitfall: Treating the OWASP Top 10 as a Compliance Checklist Rather Than a Threat Model
Problem: Checking "we have input validation" as a one-time box without ongoing verification (tests, scans) gives false assurance while the underlying risk category remains unaddressed for new code paths.
Recommended approach: Wire each category's primary control into CI as an enforced gate (SCA scanning, SAST rules, dependency signing verification) so coverage does not silently regress - see CI/CD Patterns.
Pitfall: Focusing Only on Injection and Ignoring Access Control and Configuration
Problem: Engineering teams often over-index on classic injection defenses (parameterized queries) while under-investing in access control and configuration review - precisely the two categories now ranked highest in 2025.
Recommended approach: Explicitly review authorization logic and deployment configuration (cloud IAM policies, container security context, CORS policy) with the same rigor historically reserved for injection defenses.
Pitfall: Assuming a Rare, Slow-Moving Top 10 List Means Static Guidance
Problem: Treating a single training/review session on an older Top 10 edition as permanently sufficient misses category reordering and new entries (like Software Supply Chain Failures in 2025) that reflect real, current attacker behavior.
Recommended approach: Revisit the current official list (https://owasp.org/Top10/) periodically and update internal security review checklists to match the current edition rather than an internalized older version.
Testing Strategies
- Automated SAST/DAST in the pipeline: Combine static analysis (SAST) for code-level issues (A05 Injection, A08 Integrity Failures) with dynamic analysis (DAST, e.g., OWASP ZAP) against a running instance for A01/A02-class issues that only manifest at runtime.
- Authorization-specific test suites: Write explicit tests asserting that User A cannot access User B's resources (IDOR regression tests) - this is rarely caught by generic functional tests and must be deliberate.
- Dependency and artifact provenance verification tests: Assert in CI that signature verification and SBOM generation steps actually pass/fail correctly (test the control itself, not just its presence).
- Fault injection for A10: Deliberately inject exceptions/timeouts into dependent services during integration testing (see Integration Testing Strategies) to verify the system fails closed rather than open.
- Regular external penetration testing: Complements automated scanning by finding logic flaws (A06 Insecure Design) that tools cannot reason about.
Performance, Security & Scalability Considerations
- Authorization checks at scale: Centralize policy evaluation (e.g., a policy engine or well-tested authorization library) rather than duplicating access-control logic per endpoint, which becomes both a performance and consistency liability as the API surface grows.
- Supply chain scanning cost: SCA and SBOM generation add pipeline time; cache scan results keyed on lockfile hash to avoid rescanning unchanged dependency trees on every commit.
- Logging volume vs. signal: High-volume security event logging (A09) must balance completeness against log ingestion cost and alert fatigue - prioritize logging decisions (auth failures, privilege changes) over routine successful requests.
- Fail-closed error handling under load: Ensure that fail-closed exception handling (A10) does not itself become a denial-of-service vector under high error rates (e.g., an overly aggressive lockout policy triggered by transient upstream failures).
Edge Cases & Advanced Usage
- Multi-region/multi-tenant SSRF risk (A01): Outbound request allowlists must account for cloud metadata endpoints (e.g.,
169.254.169.254) which are common SSRF targets to exfiltrate cloud credentials - explicitly block link-local and internal ranges by default. - Supply chain risk in AI/LLM-assisted development (A03/A08): AI code-generation tools may suggest package names that do not exist or are typosquatted; verify package names and provenance before adding any AI-suggested dependency.
- Distributed exception handling (A10): In a microservices topology, an unhandled exception in one service must not cause an upstream service to silently treat a security-relevant call (e.g., an authorization check) as successful by default - design explicit timeout/error handling that defaults deny for security-critical calls.
- Legacy systems unable to adopt modern crypto (A04): When constrained to maintain compatibility with legacy clients using deprecated algorithms, isolate the legacy path behind additional compensating controls (network segmentation, reduced privilege) rather than weakening the primary system's cryptographic baseline.
When Not to Use / Alternatives
The OWASP Top 10 is a prioritization tool, not an exhaustive security standard.
| Dimension | OWASP Top 10:2025 | Full Threat Modeling (STRIDE/PASTA) | Compliance Framework (SOC 2, PCI-DSS, ISO 27001) |
|---|---|---|---|
| Scope | Web application risk categories | System-specific, exhaustive | Organizational controls, broader than code |
| Best for | Prioritizing a security backlog, education | High-value/high-risk feature design | Regulatory/contractual requirements |
| Exhaustiveness | Top 10 by prevalence/impact only | As exhaustive as the exercise is scoped | Exhaustive within its specific domain |
Use full threat modeling for high-value features (payments, PII handling) where a prevalence-ranked top-10 list is too coarse to identify system-specific risks. Use a compliance framework when regulatory or contractual obligations require controls (audit logging retention, encryption-at-rest mandates) beyond what OWASP's awareness document covers.
Related Documentation
- Secure Coding Practices - the underlying techniques that mitigate most categories above
- Vulnerability Scanning - the automated discovery tooling (SAST/DAST/SCA/CSPM) that surfaces these risk categories in practice
- OSINT Reconnaissance - attack-surface discovery that precedes exploitation of the categories above, particularly A05 (Security Misconfiguration) and A08 (Software Supply Chain Failures)
- Penetration Testing Methodology - the authorized, human-driven testing discipline that validates whether these risks are actually exploitable in context
- Docker Best Practices - image scanning, SBOM, and signing addressing A02/A03
- CI/CD Patterns - pipeline gates enforcing SCA, signing, and scanning
- Git Best Practices - commit signing supporting supply chain integrity
- Microservices Architecture - trust boundaries relevant to A01 and A10
- Integration Testing Strategies - testing authorization and fault-injection scenarios
- FastAPI Best Practices - centralized exception handling example
Glossary
- IDOR (Insecure Direct Object Reference): An access control flaw where an application exposes a reference (ID, filename) to an internal object without verifying the requester is authorized to access it.
- SSRF (Server-Side Request Forgery): A vulnerability allowing an attacker to induce the server to make requests to unintended destinations, often internal services or cloud metadata endpoints.
- SBOM (Software Bill of Materials): A structured inventory of every component in a software artifact, used to assess supply chain risk.
- Fail closed vs. fail open: Fail closed denies access/action by default when an error occurs; fail open permits it - security-relevant checks must fail closed.
- SAST / DAST: Static and Dynamic Application Security Testing - analyzing code without execution versus testing a running instance, respectively.