Back to Cheat Sheets

โš ๏ธ Mishandling of Exceptional ConditionsNEW ยท OWASP 2025

OWASP Web Top 10 2025 ยท A10

HIGH RISK

๐Ÿ“‹ What Is It?

Mishandling of Exceptional Conditions arises when software handles errors, exceptions, and edge-case states in ways that create an exploitable gap. Attackers deliberately steer a system onto the exceptional path โ€” the least-tested, least-reviewed, least-instrumented part of the codebase โ€” because a control enforced on the happy path is frequently skipped when an exception unwinds the stack around it. The key reframing: handling errors is not merely a reliability concern. The same missing catch that crashes a service can be the missing catch that waves a request past an authorization gate.

New in 2025: earlier editions scattered the symptoms (verbose errors lived under Security Misconfiguration); 2025 promotes the root behaviour โ€” how apps respond when they leave the happy path โ€” to a first-class category.

A10OWASP 2025 Rank
CWE-755Improper Handling of Exceptional Conditions
New 2025First appearance in the Top 10

โš ๏ธ Top Attack Vectors

  • Fail-open controls: exhaust a pool or poison a cache so an authz check throws โ€” and the catch permits (CWE-636).
  • Verbose error / stack-trace leakage: a malformed input returns paths, SQL, versions, even DSN credentials (CWE-209).
  • Enumeration & timing oracles: "unknown user" answered differently (body, status, or ms of timing) from "wrong password."
  • Padding / crypto error oracles: distinguishable "bad padding" vs "bad MAC" enables byte-by-byte decryption (POODLE-class).
  • Unhandled-exception DoS & ReDoS: one malformed input crashes a worker or pins a CPU core (CWE-248, CWE-1333).
  • Resource leaks & half-committed state: exception before release drains the pool; no rollback corrupts records.

๐Ÿ”ด Attack Flow

1. Probe โ€” send malformed / oversized / boundary input
โ†“
2. Observe โ€” status codes, error bodies, timing, side effects
โ†“
3. Trigger โ€” force a dependency to fail or a check to throw
โ†“
4. Exploit โ€” bypass the skipped control, decrypt via the oracle, or crash
โ†“
5. IMPACT: authz bypass, disclosure, or denial of service โ€” no "big" bug needed

โŒ Vulnerable Code

// Java โ€” the catch block IS the whole vulnerability (fail-open) boolean isAdmin; try { isAdmin = roleService.check(user, "admin"); // may throw on DB error } catch (Exception e) { isAdmin = true; // FAIL-OPEN: error == allow } if (isAdmin) { renderAdminPanel(); } // Attacker exhausts the connection pool so check() throws -> granted admin

โœ… Secure Code

// Java โ€” FAIL CLOSED: the allow branch needs an explicit successful true public boolean canAccess(User user, Document doc) { try { return authzService.check(user, doc); // true only on success } catch (Exception e) { String id = UUID.randomUUID().toString(); log.error("authz check failed, denying by default id={}", id, e); return false; // error == DENY, generic message out } } // Client sees {"error":"Service unavailable","errorId": id}; full detail -> logs only

โœ“ Prevention Checklist

  • Fail closed: any error/timeout in a security decision defaults to deny
  • Centralise error handling โ€” one handler per boundary + a last-resort handler
  • Generic message + error ID to clients; full detail to server-side logs only
  • Deterministic cleanup: try/finally, context managers, defer, RAII on every path
  • Atomic transactions with rollback โ€” no half-committed state
  • Never swallow exceptions; catch specific, handle or re-throw
  • Kill oracles: uniform responses & timing; constant-time compares; authenticated encryption
  • Bound input size, type, depth & encoding; use ReDoS-safe (linear-time) regexes
  • Timeouts, bounded retries, circuit breakers โ€” with safe fallbacks
  • Debug off in prod; test the error path (fault injection, fuzzing, oracle checks)

๐Ÿ” Detection & Tools

Fuzzing (AFL/boofuzz) Chaos / fault injection Burp Suite RE2 (linear regex) Sentry Error-rate alerting

How to Test:

  • Force dependencies to time out/error and assert the app fails closed and cleans up
  • Assert login/reset responses & timings are indistinguishable for valid vs invalid accounts
  • Loop error-triggering inputs and assert pools/handles return to baseline (no leaks)
Key Takeaway: The error path is a security boundary โ€” treat it with the same rigour as the happy path. When a security-relevant operation cannot complete, the only safe answer is "no." Stay quiet to clients, verbose to logs, and make every failure uniform so it can't become an oracle.
Myth to drop: "Catching every exception makes code safer." A broad catch that swallows the error and continues is often worse than crashing โ€” it hides attacks, leaves state inconsistent, and can flip a fail-closed control into fail-open.