Systematic testing of error handling paths, malformed inputs, and boundary conditions. Load during Phase 4 testing to discover information disclosure and unexpected behavior in error handlers.
{FINDINGS}/tmp/negative-testing-results.json# Normal: {"id": 123}
{"id": "123"} # string instead of int
{"id": [123]} # array instead of scalar
{"id": {"$gt": 0}} # NoSQL operator
{"id": null}
{"id": true}
{"id": -1}
{"id": 0}
{"id": 99999999999999} # overflow
Gate: Different error format than other fields? Different backend - test separately.
# Remove each required field one at a time - which ones produce stack traces?
# Add unexpected fields: {"id": 123, "admin": true, "role": "admin", "internal": true}
Gate: Server accepts extra fields silently? Mass assignment - escalate immediately.
# UTF-8 overlong encoding
# Null bytes: "field\x00value"
# Unicode normalization: "admin" vs "ɑdmin" (U+0251)
# RTL override characters
Gate: Response differs from standard rejection? Parser confusion - dig deeper.
For every POST/PUT endpoint, send the body with each:
application/xml | text/xml (with XXE payload) | application/x-www-form-urlencoded
multipart/form-data | text/plain | (empty) | (omitted entirely)
Gate: Endpoint accepts XML when documented as JSON-only? XXE entry point.
# If GET works: try POST, PUT, DELETE, PATCH, OPTIONS, HEAD, TRACE
# If POST works: try GET with params in query string
# Test: X-HTTP-Method-Override: DELETE on a POST request
Gate: DELETE works without auth where GET requires it? Auth bypass finding. TRACE returns 200? Header reflection.
| Test | Look for |
|---|---|
| Expired token | Stack trace, secret leak in decode error |
| Modified JWT claims | Error reveals which claim failed |
alg: none | 200 = critical auth bypass |
| Empty Authorization header | Different error than missing header = info leak |
| Two Authorization headers | Which one wins? Request smuggling vector |
| Token from different env | Error reveals env name or key ID |
| 10KB+ token | Buffer overflow, memory error, stack trace |
Gate: Any 200 on malformed auth? Stop everything - validate as auth bypass.
Origin: https://evil.com # with Host: target.com
Host: target.com\r\nHost: evil.com # duplicate
X-Forwarded-Host: evil.com
X-Forwarded-For: 127.0.0.1
X-Original-URL: /admin
X-Rewrite-URL: /admin
Gate: X-Original-URL returns admin content? Path traversal finding.
| Signal | Action |
|---|---|
| Stack trace | Info disclosure finding. Extract framework, version, file paths. |
| DB error message | SQLi vector or DB version disclosure. Test injection. |
| Internal IP in error | Network architecture disclosure. Document. |
| File path in error | OS + deployment path disclosure. Document. |
| "null"/"undefined" where value expected | Unhandled exception. Fuzz harder. |
| Different error format than siblings | Different backend service. Test separately. |
| Request param echoed in error | Reflected content. Test XSS. |
| Response time > 5s on malformed input | Potential ReDoS or resource exhaustion. Measure. |
| 500 on specific input only | Unhandled exception. Investigate that input class. |
{
"endpoint": "/api/users",
"tests_run": 15,
"findings": [
{
"test": "type_confusion_null",
"input": "{\"id\": null}",
"response_code": 500,
"response_body_snippet": "TypeError: Cannot read property 'toString' of null at /app/src/users/service.js:42",
"finding_type": "information_disclosure",
"severity_estimate": "low",
"feeds_hypothesis": "Internal file path revealed - confirms Node.js Express backend",
"observation_type": "error_message"
}
]
}
Gate: Any finding with severity >= Medium? Route directly to Phase 5 validation. Everything else feeds Phase 4b hypothesis refresh.