Design Partner Program
GUIDE · REST API SECURITY

REST API security testing: every method, every field, every caller.

REST makes APIs predictable: resources in the path, verbs in the method, state in the body. That predictability is what attackers rely on. This guide breaks a REST request into the parts that get attacked, lists test cases for each HTTP method, and shows what a secure response looks like.

ANATOMY OF AN ATTACK SURFACEone request
PATCH MethodOverrides, unexpected verbs
/v2/accounts/acc_A Path IDSwap for another owner's
?expand=owner,billing QueryWiden scope, unbounded size
Authorization: Bearer … IdentityMissing, expired, other role
{ "owner_id": "usr_B" } BodyFields the client never sends
← 200 { …, "internal": … } ResponseExtra fields, verbose errors
Six places to attack in one line of HTTP. A scanner that only fuzzes the body is testing one of them.
01 · TEST CASES BY METHOD

REST API Security Test Cases for Every HTTP Method

Each verb carries its own risks. Pick a method to see what to test, the request to send and the response a secure API returns.

Reads leak data: other users' objects, extra fields, and whole collections. API1 · API3 · API4 · API9 (2023)
TEST SEND SECURE RESPONSE

Object ownership

Swap the ID for another user's object.
GET /v2/accounts/acc_B Authorization: <alice> 404 Not found. Don't confirm the object exists.

Excessive data exposure

Compare response fields to what the client shows.
GET /v2/users/me 200 Only documented fields; no hashes, internal flags or tokens.

Pagination limits

Ask for far more than any client would.
GET /v2/accounts?limit=100000 400 Or capped to the documented maximum.

Filter injection

Try to widen the filter past the caller's scope.
GET /v2/invoices?tenant_id=* 403 Tenant always taken from the token, never the query.
02 · ONE RESOURCE, TEN TESTS

REST API Security Test Run: Expected vs Actual on One Resource

Ten tests against /v2/accounts/{id}, run as three identities. A test passes when the actual response matches the secure one. Watch which status codes give the flaws away.

accounts-api · staging identities: alice (owner) · bob (other tenant) · anon
Run0/10Pass0Fail0
# REQUEST AS EXPECTED ACTUAL VERDICT
01 GET /v2/accounts/acc_AOwner reads own account alice 200 ·· Pending
02 GET /v2/accounts/acc_ANo token anon 401 ·· Pending
03 GET /v2/accounts/acc_AOther tenant reads by ID bob 404 ·· Pending
04 GET /v2/accounts?limit=100000Unbounded page size alice 400 ·· Pending
05 PATCH /v2/accounts/acc_A {plan}Change plan without billing role alice 403 ·· Pending
06 PATCH /v2/accounts/acc_A {owner_id}Reassign ownership alice 400 ·· Pending
07 PUT /v2/accounts/acc_AOther tenant overwrites bob 404 ·· Pending
08 DELETE /v2/accounts/acc_AOther tenant deletes (dry run) bob 404 ·· Pending
09 POST … X-HTTP-Method-Override: DELETEVerb smuggling bob 405 ·· Pending
10 GET /v2/accounts/acc_ZZZMissing object, error body alice 404 ·· Pending
Press play to run ten tests. Each one asserts an exact status code.
00:00 / 00:20

Illustrative run · synthetic API and data · 20 s replay

03 · WHAT A FINDING LOOKS LIKE

Mass Assignment Example: One Extra Field in a PATCH

The profile endpoint binds the request body straight onto the user model. The UI never sends role, so nobody noticed the API accepts it.

How to prove API endpoint abuse →

Illustrative finding · synthetic data

Users API · privilege escalation via mass assignment API3:2023 · CWE-915
Critical Validated
SETUP
Identity: alice, role member. The web client's profile form sends name and avatar only.
BASELINE
A normal profile update succeeds.PATCH /v2/users/me { "name": "Alice R" } → 200
INJECT
The same request with one extra field taken from the GET response.PATCH /v2/users/me { "name": "Alice R", "role": "admin" }
RESPONSE
Accepted. The user model binds every field in the body.200 OK { "id": "usr_A", "role": "admin" }
CONFIRM
alice now calls an admin-only endpoint successfully. Read-only call; the role was reverted immediately after.GET /v2/admin/users → 200 (list redacted)
SCANNER
The spec doesn't list role as writable, so spec-driven fuzzing never sent it.
Fix and retest: bind only an explicit allowlist of writable fields per role; the PATCH is replayed and now returns 400 with role rejected.
04 · SECURE RESPONSES

REST API Status Codes: What a Secure Response Looks Like

Test assertions should name the exact code. A 200 where a 404 belongs is a finding, and so is an error that leaks more than it should.

401Unauthorized

No credentials, or credentials that are invalid or expired.

RED FLAG · 200 with a missing or expired token.
403Forbidden

Valid caller, but this role may not perform this function.

RED FLAG · Used for other users' objects, confirming they exist.
404Not Found

Object doesn't exist, or exists but belongs to someone else.

RED FLAG · 200 for another tenant's object.
400Bad Request

Unknown, protected or malformed fields in the body.

RED FLAG · 200 that silently accepts protected fields.
405Method Not Allowed

A verb or override the resource doesn't support.

RED FLAG · Override headers that change the method.
413Content Too Large

Body beyond the documented maximum.

RED FLAG · Large bodies parsed before being rejected.
429Too Many Requests

Caller or target exceeds its rate limit.

RED FLAG · No limit on login, invite, OTP or export.
5xxServer error

Should be rare, and generic when it happens.

RED FLAG · Stack traces, SQL or internal hostnames in the body.
05 · THE WORKFLOW

How to Test a REST API: From OpenAPI Spec to CI

Six steps that turn one-off testing into a suite that runs on every pull request.

Choosing an API security testing tool →
01

Reconcile spec and traffic

Compare the OpenAPI spec with real traffic and gateway routes. Undocumented endpoints are often the least protected.

02

Define identities

At least two users per role across two tenants, plus anonymous. Keep their tokens fresh automatically.

03

Model ownership and writable fields

Record who owns each seeded object and which fields each role may write. The spec doesn't say.

04

Generate method-level tests

Expand each endpoint into the tests on this page for every method it supports, plus overrides.

05

Assert exact responses

Name the expected status code and allowed fields for each test. A 200 is not a pass by default.

06

Run in CI and retest

Run on every pull request that touches routes or models; failures block merge, fixes rerun automatically.

06 · WHERE HAYROK FITS

REST API Validation That Knows Who's Calling

Hayrok reads your OpenAPI spec and live traffic, runs the method-level tests on this page as every identity you define, and asserts on ownership and exact status codes. Each failure is a validated finding with the request pair attached.

01

Spec plus traffic

Builds the endpoint inventory from your OpenAPI spec and observed traffic, flagging the difference.

02

Every method, every identity

Runs method-level scenarios as each role and tenant, including verb overrides.

03

Ownership-aware assertions

Knows which identity owns each test object, so a cross-tenant 200 is a failure.

04

Safe writes

PUT, PATCH and DELETE run only on seeded test objects inside approved scope.

05

Evidence in CI

Failures post to the pull request with the request pair; Evidence Fabric keeps the record.

07 · FAQ

REST API Security Testing FAQ

Testing a REST API the way an attacker would: changing object IDs, adding fields, switching HTTP methods, calling as different users and pushing limits, then checking that every response is the secure one.

BRING ONE OPENAPI SPEC

Run every method-level test on your REST API, as every caller.

Share a spec and three test identities. We'll run the suite against staging and show you every expected-versus-actual mismatch with its request pair.