HUNT-EXCEPTIONAL-CONDITIONS — Verbose Errors / Fail-Open (A10:2025)
What actually pays
Well-built apps catch errors and return a clean, generic message. A broken app,
when handed input it didn't expect, throws an unhandled exception and renders a
developer error page straight to the client — leaking the stack trace, the
ORM/query internals, server-side file paths, and framework/library versions.
That disclosure is the finding (and it arms SQLi/RCE/path attacks next).
Recon
Any endpoint that parses input is a candidate; the richest are:
JSON APIs that expect typed fields: POST /api/* with {numbers, ids, enums}
Endpoints with numeric/id path or query params: /item/{id}, ?page=, ?quantity=
Search / filter / sort params
File or content-type sensitive uploads
Attack — send what the code didn't anticipate
Take a known-good request and break ONE assumption at a time:
- Wrong type: a field the app expects to be a number/string is sent as an
array or object —
{"rating":"x","comment":[1,2,3]}, {"quantity":{}}.
- Malformed body: truncated/!invalid JSON, an unterminated string, a stray
brace, a wrong/missing Content-Type.
- Boundary/oversized: a very long string, a huge/negative/overflow number.
- Null byte / control chars embedded in a value.
POST /api/Feedbacks {"rating":"notanumber","comment":[1,2,3]}
GET /item/' OR /item/%00 (also exercises the error path)
Watch the RESPONSE BODY, not just the status: a 500 (or even a 200/400) whose
body contains a stack trace or framework error page is the signal.
What counts as a leak (the success signal)
A finding is confirmed when the response body contains a cross-framework error-disclosure signature:
- Node/Express + Sequelize:
SequelizeDatabaseError, node_modules/sequelize,
a JS stack with internal paths.
- PHP:
<b>Warning</b> ... /var/www/.../file.php on line N.
- Python:
Traceback (most recent call last), werkzeug.exceptions.
- Java:
at com.app.Foo(Foo.java:42) stack frames.
- .NET:
Server Error in '/' Application, a [System.XxxException: ...] YSOD.
A clean JSON error ({"error":"Invalid input"}) with no internals is NOT a
finding — that's correct handling. Disclosure of internal structure is.
Validation discipline
- Capture the exact leaked artifact (path, ORM class, version, stack frame) —
that's the evidence. "It returned 500" alone is not disclosure.
- Note what the leak enables next (e.g. a disclosed SQL error → hunt-sqli; a
disclosed absolute path → hunt-lfi).
1---2name: hunt-exceptional-conditions3description: Hunt mishandling of exceptional conditions — feed an endpoint malformed/unexpected input (wrong type, broken JSON, oversized field, null byte) and make it fail OPEN or leak internals: a verbose stack-trace / framework error page that discloses ORM internals, server file paths, library versions, or a language traceback. Use on any input-accepting endpoint (JSON APIs, forms, query params). Medium-High when the leak exposes internal structure that arms a deeper attack.4---5
6# HUNT-EXCEPTIONAL-CONDITIONS — Verbose Errors / Fail-Open (A10:2025)
7
8## What actually pays
9
10Well-built apps catch errors and return a clean, generic message. A broken app,
11when handed input it didn't expect, throws an unhandled exception and renders a
12**developer error page** straight to the client — leaking the stack trace, the
13ORM/query internals, server-side file paths, and framework/library versions.
14That disclosure is the finding (and it arms SQLi/RCE/path attacks next).
15
16## Recon
17
18Any endpoint that parses input is a candidate; the richest are:
19
20```
21JSON APIs that expect typed fields: POST /api/* with {numbers, ids, enums}
22Endpoints with numeric/id path or query params: /item/{id}, ?page=, ?quantity=
23Search / filter / sort params
24File or content-type sensitive uploads
25```
26
27## Attack — send what the code didn't anticipate
28
29Take a known-good request and break ONE assumption at a time:
30
31- **Wrong type:** a field the app expects to be a number/string is sent as an
32 array or object — `{"rating":"x","comment":[1,2,3]}`, `{"quantity":{}}`.
33- **Malformed body:** truncated/!invalid JSON, an unterminated string, a stray
34 brace, a wrong/missing Content-Type.
35- **Boundary/oversized:** a very long string, a huge/negative/overflow number.
36- **Null byte / control chars** embedded in a value.
37
38```
39POST /api/Feedbacks {"rating":"notanumber","comment":[1,2,3]}
40GET /item/' OR /item/%00 (also exercises the error path)
41```
42
43Watch the RESPONSE BODY, not just the status: a 500 (or even a 200/400) whose
44body contains a stack trace or framework error page is the signal.
45
46## What counts as a leak (the success signal)
47
48A finding is confirmed when the response body contains a cross-framework error-disclosure signature:
49
50- **Node/Express + Sequelize:** `SequelizeDatabaseError`, `node_modules/sequelize`,
51 a JS stack with internal paths.
52- **PHP:** `<b>Warning</b> ... /var/www/.../file.php on line N`.
53- **Python:** `Traceback (most recent call last)`, `werkzeug.exceptions`.
54- **Java:** `at com.app.Foo(Foo.java:42)` stack frames.
55- **.NET:** `Server Error in '/' Application`, a `[System.XxxException: ...]` YSOD.
56
57A clean JSON error (`{"error":"Invalid input"}`) with no internals is NOT a
58finding — that's correct handling. Disclosure of internal structure is.
59
60## Validation discipline
61
62- Capture the exact leaked artifact (path, ORM class, version, stack frame) —
63 that's the evidence. "It returned 500" alone is not disclosure.
64- Note what the leak enables next (e.g. a disclosed SQL error → hunt-sqli; a
65 disclosed absolute path → hunt-lfi).