A security test suite should spend as much effort proving that bad requests fail as proving good ones succeed. Negative tests cover expired and tampered tokens, wrong roles, oversized or malformed input, replayed requests and attempts to set fields the client should not control.
Why negative tests get skipped
Features are specified by what they allow. The ticket says a user can upload an avatar, so the test uploads an avatar. Nobody writes a ticket that says a user cannot upload a ten gigabyte script.
Negative cases have to come from a checklist or a threat model, because the feature description will not supply them.
Authentication negatives
- No token, empty token, malformed token.
- Expired token, and a token that is valid but not yet active.
- Token signed with a different key or with the algorithm set to none.
- Token for a deleted or disabled user.
- Session after logout and after a password change.
Each should return the same generic refusal, with no hint about which check failed.
Authorization negatives
- A valid user calls an admin route.
- A valid user requests another user's id.
- A user sends a role or owner field in the request body and expects it to stick. This is mass assignment, and the test should show the field is ignored.
- A downgraded plan keeps calling a paid feature.
Input negatives
- Empty, null, wrong type, extra fields.
- Strings far over the length limit and numbers at and beyond the integer boundary.
- Unicode oddities such as combining marks, right to left controls and null bytes.
- Nested structures deeper than your parser expects.
- Uploads with a wrong content type, a double extension or a mismatch between declared and actual type.
Assert both the refusal and that nothing was stored. A request that returns 400 after writing half a record is still a bug.
Abuse and replay negatives
- The same one time token or webhook delivery sent twice.
- A signed request with the body changed by one byte.
- A burst above the rate limit returns the throttle response, and the legitimate user recovers after the window.
- Concurrent requests that try to spend the same balance.
Where to get more cases
The OWASP Web Security Testing Guide is a good prompt list when you run out of ideas, and every incident or pentest finding you receive should add at least one new negative test. Ask after each report: which request proved the bug, and is that request now in the suite?
Keep the cases readable
Name tests by the attack, such as test_expired_token_is_rejected. A failure in CI should tell a reader what was attempted. Group them in a security folder so a reviewer can scan the list and spot what is missing.
Quick check
Is a 400 or 403 status enough to pass?
No. Also check there are no side effects: no row written, no email sent, no job queued, and no detail in the error body that helps an attacker.
Sources
Last reviewed: 19 October 2026.