What Changed: 2021 vs 2025
| 2021 | → | 2025 | Change |
|---|---|---|---|
| A01 Broken Access Control | → | A01 Broken Access Control | Retained #1; absorbed SSRF |
| A05 Security Misconfiguration | ↑ | A02 Security Misconfiguration | Rose from #5 to #2 |
| A06 Vulnerable Components | ↑ | A03 Supply Chain Failures (NEW) | Renamed & expanded |
| A02 Cryptographic Failures | ↓ | A04 Cryptographic Failures | Dropped from #2 to #4 |
| A03 Injection | ↓ | A05 Injection | Dropped from #3 to #5 |
| A04 Insecure Design | ↓ | A06 Insecure Design | Dropped from #4 to #6 |
| A07 Auth Failures | → | A07 Authentication Failures | Minor rename |
| A08 Integrity Failures | → | A08 Integrity Failures | Minor rename |
| A09 Logging/Monitoring | → | A09 Logging & Alerting | Monitoring → Alerting |
| A10 SSRF | → | Merged into A01 | Consolidated |
| — | ★ | A10 Exceptional Conditions (NEW) | Brand new category |
Rank Trends: 2017 → 2021 → 2025
Click any line to highlight it. Gray lines show retired categories.
A bump chart showing how each OWASP Top 10 category changed rank across the 2017, 2021, and 2025 editions. Broken Access Control rose from 5 to 1. Injection fell from 1 to 5. Security Misconfiguration rose from 6 to 2.Key Takeaways
- Broken Access Control remains #1 and now absorbs SSRF (formerly its own category)
- Security Misconfiguration surged to #2 — cloud and container sprawl makes misconfigs the dominant risk
- NEW: Software Supply Chain Failures (A03) expands far beyond "vulnerable components" to cover compromised build pipelines and malicious dependencies
- Injection dropped from #3 to #5 but still has the most CVEs of any category (62,000+)
- NEW: Mishandling of Exceptional Conditions (A10) — fail-open logic, verbose errors, and state corruption
A01:2025 – Broken Access Control
Risk Level: Critical · Found in 100% of tested apps · 40 CWEs · 32,654 CVEs
Description: Users can act outside their intended permissions — accessing unauthorized data, modifying records, or escalating privileges. Now includes SSRF (formerly A10:2021).
Common Vulnerabilities:
• Bypassing access control checks by modifying URLs, API requests, or internal state
• Insecure Direct Object References (IDOR) — viewing another user's data by changing an ID
• Missing access controls for POST, PUT, DELETE API endpoints
• Elevation of privilege — acting as admin when logged in as a regular user
• CORS misconfiguration allowing unauthorized API access
• SSRF — fetching internal resources via user-controlled URLs
Quick Fixes:
• Deny by default — except for public resources
• Implement access control once and reuse throughout the application
• Enforce record ownership — don't let users CRUD any record
• Invalidate JWT tokens on the server after logout; use short-lived tokens
• Rate limit API calls and validate/allowlist URLs for SSRF prevention
• Log access control failures and alert on repeated violations
# Vulnerable: no ownership check (IDOR)
def get_account(request, acct_id):
return Account.objects.get(id=acct_id)
# Secure: verify record ownership
def get_account(request, acct_id):
account = Account.objects.get(id=acct_id)
if account.owner != request.user:
raise PermissionDenied("Forbidden")
return account
A02:2025 – Security Misconfiguration
Risk Level: High · Found in 100% of tested apps · Rose from #5 (2021) to #2
Description: Insecure defaults, incomplete configurations, open cloud storage, misconfigured HTTP headers, and verbose error messages. Cloud and container sprawl has made this the second-most critical risk.
Common Vulnerabilities:
• Missing security hardening across the application stack
• Unnecessary features enabled (ports, services, accounts, privileges)
• Default accounts and passwords still enabled
• Error handling revealing stack traces to users
• Missing or misconfigured security headers (CSP, X-Frame-Options)
• Cloud storage permissions left open (public S3 buckets)
Quick Fixes:
• Implement a repeatable hardening process for all environments
• Use a minimal platform — remove unused features and frameworks
• Send security directives to clients (Content-Security-Policy, HSTS)
• Automate configuration verification across all environments
• Review and update configs as part of the patch management cycle
<!-- BAD: Default credentials + verbose errors -->
<user username="admin" password="admin" roles="admin"/>
<customErrors mode="Off" />
<!-- GOOD: Custom error pages, no details exposed -->
<customErrors mode="RemoteOnly" defaultRedirect="GenericError.htm">
<error statusCode="500" redirect="InternalError.htm"/>
</customErrors>
A03:2025 – Software Supply Chain Failures NEW
Risk Level: Critical · #1 in community surveys · Highest incidence rate (5.19%)
Description: Expands far beyond the former "Vulnerable and Outdated Components" (A06:2021) to cover the entire software supply chain — compromised build pipelines, malicious dependencies, unverified packages, and developer workstation attacks.
Common Vulnerabilities:
• No SBOM — no visibility into transitive dependencies
• Using outdated, unsupported, or vulnerable software
• Components from untrusted or unverified sources
• Compromised CI/CD pipelines or build systems
• Lack of separation of duties in development workflows
• No monitoring of vulnerability databases (CVE, NVD, OSV)
Quick Fixes:
• Generate a Software Bill of Materials (SBOM) for complete inventory
• Continuously monitor CVE, NVD, and OSV vulnerability databases
• Obtain components only from trusted sources with verified signatures
• Harden CI/CD pipelines, code repos, and dev workstations with MFA
• Use staged/canary deployments rather than simultaneous rollouts
• Implement risk-based patching — not fixed monthly schedules
# Generate SBOM for your project
npm sbom --sbom-format cyclonedx
pip install cyclonedx-bom && cyclonedx-py
# Audit dependencies for known vulnerabilities
npm audit
pip-audit
snyk test
A04:2025 – Cryptographic Failures
Risk Level: High · 32 CWEs · Dropped from #2 (2021) to #4
Description: Sensitive data exposed due to missing encryption, weak algorithms, or poor key management. Includes data in transit and at rest.
Common Vulnerabilities:
• Data transmitted in clear text (HTTP, SMTP, FTP)
• Old or weak algorithms (MD5, SHA1, DES, RC4)
• Default or weak crypto keys; no key rotation
• Improper certificate validation
• Passwords stored with weak or unsalted hashes
• Sensitive data cached unnecessarily
Quick Fixes:
• Encrypt all data in transit with TLS 1.2+ and forward secrecy (PFS)
• Hash passwords with Argon2id, scrypt, or bcrypt
• Use authenticated encryption (AES-GCM), not just encryption
• Implement proper key management and rotation
• Disable caching for responses containing sensitive data
• Plan for post-quantum cryptography migration
# BAD: Unsalted MD5
import hashlib
pw_hash = hashlib.md5(password.encode()).hexdigest()
# GOOD: Argon2id (memory-hard, GPU-resistant)
from argon2 import PasswordHasher
ph = PasswordHasher()
pw_hash = ph.hash(password)
ph.verify(pw_hash, password) # Verification
A05:2025 – Injection
Risk Level: Critical · Found in 100% of tested apps · 62,445 CVEs (most of any category)
Description: Untrusted data sent to an interpreter as part of a command or query. Includes SQL injection (14K+ CVEs), XSS (30K+ CVEs), OS command injection, NoSQL injection, and LDAP injection.
Common Vulnerabilities:
• User input not validated, filtered, or sanitized
• Dynamic queries without parameterized interfaces
• Hostile data used in ORM search parameters
• Hostile data concatenated into SQL, commands, or stored procedures
Quick Fixes:
• Use parameterized queries (prepared statements) or safe ORMs
• Use positive server-side input validation (allowlists)
• Escape special characters for the target interpreter
• Use LIMIT and other SQL controls to prevent mass data disclosure
• Implement Content Security Policy (CSP) to mitigate XSS
// BAD: String concatenation (SQL injection)
String query = "SELECT * FROM users WHERE id='"
+ request.getParameter("id") + "'";
// Attacker sends: ' OR '1'='1
// GOOD: Parameterized query
PreparedStatement stmt = conn.prepareStatement(
"SELECT * FROM users WHERE id = ?");
stmt.setString(1, request.getParameter("id"));
A06:2025 – Insecure Design
Risk Level: High · Dropped from #4 (2021) to #6
Description: Missing or ineffective security controls at the architecture level. An insecure design cannot be fixed by a perfect implementation — the needed security controls were never created.
Quick Fixes:
• Establish a Secure Development Lifecycle (SDLC) with AppSec professionals
• Use threat modeling for critical auth, access control, and business logic flows
• Integrate security language and controls into user stories
• Write unit and integration tests that validate resistance to the threat model
• Segregate tier layers based on exposure and protection needs
• Limit resource consumption by user or service
# BAD: No rate limiting on login
@app.route('/login', methods=['POST'])
def login():
if authenticate(user, pw):
return redirect('/dashboard')
return "Invalid credentials", 401
# GOOD: Rate-limited login
from flask_limiter import Limiter
limiter = Limiter(app)
@app.route('/login', methods=['POST'])
@limiter.limit("5 per minute")
def login():
if authenticate(user, pw):
return redirect('/dashboard')
return "Invalid credentials", 401
A07:2025 – Authentication Failures
Risk Level: Critical · 36 CWEs · Renamed from "Identification and Authentication Failures"
Description: Weaknesses in authentication and session management that allow attackers to compromise passwords, keys, or sessions.
Common Vulnerabilities:
• Permits credential stuffing or brute force attacks
• Allows default, weak, or well-known passwords
• Weak credential recovery processes
• Passwords stored without proper hashing
• Missing or ineffective multi-factor authentication (MFA)
• Session IDs exposed in URLs or not invalidated after logout
Quick Fixes:
• Implement multi-factor authentication (MFA)
• Never deploy with default credentials
• Check passwords against the top 10,000 worst passwords list
• Align with NIST 800-63 password guidelines
• Limit or delay failed login attempts (without creating DoS)
• Regenerate session IDs after login; invalidate on logout and timeout
# BAD: Hard-coded credentials, session in URL
DB_PASS = "password123"
redirect(f"/dashboard?session_id={sid}")
# GOOD: Secure session management
import secrets
session_id = secrets.token_urlsafe(32)
response.set_cookie('session_id', session_id,
httponly=True, secure=True, samesite='Strict')
A08:2025 – Software or Data Integrity Failures
Risk Level: High · Focuses on trust boundaries and verification at the code/data level
Description: Code and infrastructure that does not protect against integrity violations — insecure deserialization, unsigned updates, and unverified CI/CD pipelines.
Quick Fixes:
• Use digital signatures to verify software and data integrity
• Ensure libraries and dependencies come from trusted repositories
• Use supply chain security tools (OWASP Dependency-Check, Snyk)
• Properly segregate and secure CI/CD pipeline access
• Never send unsigned/unencrypted serialized data to untrusted clients
• Review code and config changes to prevent malicious insertion
# BAD: Deserializing untrusted data
import pickle
user_obj = pickle.loads(request.data) # RCE risk!
# GOOD: Safe format + integrity verification
import json, hmac, hashlib
data = json.loads(request.data)
expected = hmac.new(SECRET, request.data, hashlib.sha256).hexdigest()
if not hmac.compare_digest(request.headers['X-Sig'], expected):
raise IntegrityError("Tampered data")
A09:2025 – Security Logging and Alerting Failures
Risk Level: Medium · Renamed to emphasize actionable alerting (was "Monitoring")
Description: Insufficient logging, detection, and alerting capabilities. Without proper logging, breaches cannot be detected and incidents cannot be responded to effectively.
Quick Fixes:
• Log all login attempts, access control failures, and input validation failures with user context
• Use a centralized log management solution (SIEM)
• Ensure high-value transactions have tamper-proof audit trails
• Establish monitoring dashboards and alerting thresholds
• Adopt an incident response plan (NIST 800-61r3)
• Ensure pen test and DAST scans trigger alerts
# BAD: No logging
def login(username, password):
if not authenticate(username, password):
return "Login failed" # Silent failure
# GOOD: Structured logging with alerting
import logging
logger = logging.getLogger('security')
def login(username, password):
if not authenticate(username, password):
logger.warning(f"Failed login: user={username} "
f"ip={request.remote_addr}")
alert_if_threshold_exceeded(username)
return "Login failed"
logger.info(f"Successful login: user={username}")
A10:2025 – Mishandling of Exceptional Conditions NEW
Risk Level: High · 24 CWEs · Replaces SSRF (which moved into A01)
Description: Improper error handling, fail-open logic, verbose error messages exposing internals, and state corruption from unhandled edge cases. Three failure modes: prevention, detection, and response.
Common Vulnerabilities:
• Fail-open conditions — security checks default to "allow" on error
• Verbose error messages exposing database traces, file paths, stack traces
• Silent exception handling — suppressing errors while continuing in unsafe state
• Resource exhaustion from errors that don't clean up (DoS)
• State corruption in multi-step transactions when intermediate steps fail
• NULL pointer dereferences causing crashes
Quick Fixes:
• Design all security controls to "fail closed" (deny on error)
• Implement a global exception handler as a safety net
• Strip sensitive data from all user-facing error messages
• Use centralized logging and real-time monitoring for exceptions
• Test edge cases with fuzz testing and chaos engineering
• Ensure resource cleanup in all error paths (finally blocks, context managers)
# BAD: Fails open — grants access on error!
def check_auth(user, resource):
try:
return auth_service.is_allowed(user, resource)
except Exception:
return True # DANGEROUS
# GOOD: Fails closed — denies access on error
def check_auth(user, resource):
try:
return auth_service.is_allowed(user, resource)
except Exception as e:
logger.error(f"Auth check failed: {e}")
return False # Deny by default
Related Resources
Latest from the Blog
FixTheVuln Store
Study Planners Available for Both Certs
Fillable PDF study planners with domain trackers, weekly schedules, and progress tracking. Available in Standard, ADHD-Friendly, Dark Mode, and 4-Format Bundle.
CompTIA PenTest+ Planner EC-Council CEH Planner60+ certifications available — from $5.99
FixTheVuln Store
Patch Tuesday Sprint Kit
5 fillable templates for vulnerability triage, sprint planning, testing, SLA tracking, and executive reporting. Free blank templates or $4.99/mo for pre-filled intelligence with real CISA KEV data.
Try Free Templates Subscribe — $4.99/moFixTheVuln Store
Patch Tuesday Sprint Kit
5 fillable templates for vulnerability triage, sprint planning, testing, SLA tracking, and executive reporting. Free blank templates or $4.99/mo for pre-filled intelligence with real CISA KEV data.
Try Free Templates Subscribe — $4.99/moFixTheVuln Store
Patch Tuesday Sprint Kit
5 fillable templates for vulnerability triage, sprint planning, testing, SLA tracking, and executive reporting. Free blank templates or $4.99/mo for pre-filled intelligence with real CISA KEV data.
Try Free Templates Subscribe — $4.99/moCyberFolio
Choosing your next cert? Track them all in one place.
Build a shareable cybersecurity portfolio that highlights your certifications, projects, and skills — free.
Build Your Portfolio →FixTheVuln Store
Patch Tuesday Sprint Kit
5 fillable templates for vulnerability triage, sprint planning, testing, SLA tracking, and executive reporting. Free blank templates or $4.99/mo for pre-filled intelligence with real CISA KEV data.
Try Free Templates Subscribe — $4.99/moFixTheVuln Store
Patch Tuesday Sprint Kit
5 fillable templates for vulnerability triage, sprint planning, testing, SLA tracking, and executive reporting. Free blank templates or $4.99/mo for pre-filled intelligence with real CISA KEV data.
Try Free Templates Subscribe — $4.99/moFixTheVuln Store
Patch Tuesday Sprint Kit
5 fillable templates for vulnerability triage, sprint planning, testing, SLA tracking, and executive reporting. Free blank templates or $4.99/mo for pre-filled intelligence with real CISA KEV data.
Try Free Templates Subscribe — $4.99/mo