A10/Mishandling of Exceptional Conditions — OWASP Top 1000 / 11
A10
OWASP Top 10 · 2025 · NEW
Mishandling of
Exceptional Conditions
The shield held under normal conditions. Then something unexpected happened — and it failed open.
// cloudflare — 2019 — one regex, 27 minutes, 10% of the internet unprotected

On July 2, 2019, a Cloudflare WAF rule took down security for ~10% of the internet. Not a breach, not an attack — a fail-open caused by one regular expression. Click each event.

13:42
WAF rule deployed
13:42
CPU spikes 100%
13:42–14:02
WAF fails open
14:02
Global WAF kill
14:52
Rollback + fix

This is the newest OWASP Top 10 category. 24 CWEs. 769,581 occurrences. Average exploit score of 7.11 — among the highest. These bugs rarely cause visible errors. The application keeps running. It just stops being secure.

// classify the failure

An API endpoint's authorization check throws an exception when the user's role is missing from the database. The catch block logs the error and returns HTTP 200. The user proceeds without authorization. What kind of failure is this?

🔓 Broken access control
The authorization check is missing or incorrectly implemented in the endpoint logic.
💥 Fail-open error handling
The exception handler defaults to allowing the request instead of denying it when the auth check fails.
⚙️ Security misconfiguration
The role field was missing from the database due to a configuration or migration error.
📝 Logging failure
The error was logged but not acted upon, which is a monitoring and alerting problem.
// find the fail-open

Express.js middleware for authorization. The logic looks defensive — it has a try-catch. But one line turns every exception into an authorization bypass. Click it.

middleware/authorize.js
// three ways errors become vulnerabilities
step 1 of 3

Fail closed. Always.

fail open
fail closed

When your code doesn't know what to do next, the safe answer is always "deny." Never "allow." Never "continue." Never "ignore."

Auth fail-closed
Error responses
Input validation
authorize.js
click the dot
why this works
// knowledge check
1 / 4

What does "fail open" mean in a security context, and why is it dangerous for production applications?

A — The system defaults to allowing access when an error occurs — bypassing security controls silently
B — The system crashes and displays an error page, which reveals internal information to the attacker
C — The system opens a connection to an external service and fails to close it, causing resource exhaustion
// knowledge check
2 / 4

A 500 error response includes the full stack trace, database connection string, and internal file paths. What CWE does this fall under?

A — CWE-476: NULL Pointer Dereference — the application crashes because a required object reference is null
B — CWE-209: Error Message Containing Sensitive Information — internals are exposed to the attacker
C — CWE-636: Not Failing Securely — the system continues operating in an undefined and insecure state
// knowledge check
3 / 4

Why did OWASP add "Mishandling of Exceptional Conditions" as a new category in 2025 rather than keeping it under code quality?

A — Static analysis tools improved enough to detect all error handling bugs automatically in CI pipelines
B — Previous editions grouped these issues with injection attacks, but the remediation approaches differ
C — Error handling failures cause auth bypass, info disclosure, and DoS — they are security flaws, not just bugs
// knowledge check
4 / 4

Cloudflare's WAF consumed 100% CPU and stopped filtering traffic. CrowdStrike's Falcon caused 8.5 million machines to crash. What's the critical difference?

A — Scale of impact — CrowdStrike affected more devices, making it the worse incident overall
B — Fail-open vs fail-stop — Cloudflare kept running without protection, CrowdStrike stopped entirely
C — One was a regex, the other was a driver — the root cause technology is the key distinction
D — One affected servers, the other affected clients — the attack surface determines the category
// self-check complete

// the mental model

carry this into every catch block you write

When your code doesn't know what to do next, the answer is deny. Not allow. Not continue. Not ignore. Every catch block is a security decision — and the default must be closed.

Code-review check: every catch block around a security control denies by default.

🎯 the one habit

When your code doesn’t know what to do next, deny. Audit every catch block on a security path: does it allow or deny? If it allows, you have a fail-open vulnerability.

A10 · Mishandling of Exceptional Conditions · NEW 2025
Scope in 2025
Fail-open · stack traces · null deref · missing params · race conditions
A10 is new for 2025 with 24 CWEs, 769K occurrences, and a 7.11 average exploit score. Key CWEs: CWE-209 (sensitive error messages), CWE-234 (missing parameter handling), CWE-274 (insufficient privilege handling), CWE-476 (NULL pointer dereference), CWE-636 (not failing securely). These were previously classified as code quality issues — OWASP reclassified them because they directly enable auth bypass, information disclosure, and denial of service. Infrastructure matters too: WAFs that fail open under load, load balancers that drop auth headers on timeout, circuit breakers with insecure defaults, and retry logic that bypasses security checks are all A10 failures. DevOps owns the infrastructure side of fail-closed design.
First fix
Audit every catch block — does it deny or allow? Change all "allow on error" to deny
Search your codebase for catch blocks in security-critical paths: authentication, authorization, payment processing, data access. For each one, ask: "If this catch block runs, does the user get access or get denied?" If the answer is "access," you have a fail-open vulnerability. The fix is always the same: the catch block must return a denial (403, 500, redirect to login) — never a success. Use a centralized error handler that defaults to deny.
Defence in depth
Centralized error handler · generic user-facing errors · structured internal logging
Use a single, centralized error handler that catches all unhandled exceptions and returns a generic error to the user ("Something went wrong") while logging the full details internally. Never expose stack traces, file paths, database strings, or framework versions to users. Handle errors at the function level where they occur — not at a distant, high-level handler where context is lost. Validate all inputs at system boundaries before they reach business logic.

// check your error handling today

Five things you can verify right now.

Catch blocks in auth paths
Do any catch blocks in login/authorization code return success or call next()? They shouldn't.
Production error responses
Trigger a 500 error in production. Does the response contain stack traces or internal paths?
Missing parameter handling
Send a request with required parameters missing. Does the API crash, fail open, or return a clear error?
Centralized error handler
Is there a single handler that catches unhandled exceptions? Does it deny by default?
Database/service timeout behaviour
What happens when the database is unreachable? Does the app fail open or fail closed?
0 / 5