Skip to content
ZK
ZAIN KHALIL KHAN
PORTFOLIO
All projects

Interactive build

API Threat Model | Authorisation Review

API security review model that inventories endpoints and checks each for object-level authorisation on client-supplied ids, function-level authorisation on privileged routes, mass assignment, unauthenticated writes, and unbounded authentication paths.

Live demo readyAPI Security + OWASP
API SecurityOWASPBOLAAuthorisationAppSecSecure DesignCase study / interactive demo

Case study

From problem to working system

Problem

API security review model that inventories endpoints and checks each for object-level authorisation on client-supplied ids, function-level authorisation on privileged routes, mass assignment, unauthenticated writes, and unbounded authentication paths.

My role

Security engineer and full-stack developer

Solution

API security review model that inventories endpoints and checks each for object-level authorisation on client-supplied ids, function-level authorisation on privileged routes, mass assignment, unauthenticated writes, and unbounded authentication paths.

Architecture

The implementation combines the following technologies and system concerns.

API SecurityOWASPBOLAAuthorisationAppSecSecure Design

How it was built

  • Checked object-level authorisation first, because broken object-level authorisation needs no exploit: changing an id in the URL returns another tenant's record.
  • Distinguished object-level from function-level authorisation, since an endpoint can verify ownership correctly and still let a non-admin call an admin operation.
  • Detected mass assignment, where binding the whole request body lets a caller set fields such as role or tenant id.
  • Treated unauthenticated write endpoints differently for webhooks, where signature verification over the raw body is the actual control.

Security decisions

  • Checked object-level authorisation first, because broken object-level authorisation needs no exploit: changing an id in the URL returns another tenant's record.
  • Distinguished object-level from function-level authorisation, since an endpoint can verify ownership correctly and still let a non-admin call an admin operation.
  • Detected mass assignment, where binding the whole request body lets a caller set fields such as role or tenant id.
  • Treated unauthenticated write endpoints differently for webhooks, where signature verification over the raw body is the actual control.

Major challenges

  • Checked object-level authorisation first, because broken object-level authorisation needs no exploit: changing an id in the URL returns another tenant's record.
  • Distinguished object-level from function-level authorisation, since an endpoint can verify ownership correctly and still let a non-admin call an admin operation.
  • Detected mass assignment, where binding the whole request body lets a caller set fields such as role or tenant id.

Verified evidence

Results and measurable impact

  • Detected mass assignment, where binding the whole request body lets a caller set fields such as role or tenant id.
  • Treated unauthenticated write endpoints differently for webhooks, where signature verification over the raw body is the actual control.
  • Flagged authentication endpoints without rate limiting and generic failure messaging, which is what turns a login form into an enumeration oracle.
  • Paired every finding with the concrete server-side fix, such as scoping the query by the authenticated subject instead of trusting the supplied id.

No separate numeric outcome is documented, so this section shows shipped technical evidence without inventing metrics.

Screenshots and access

Product view

Interactive Demo

A scoped, fully functional recreation of this project's core feature runs below, live in your browser. Reset it, resize it, or expand it to full screen.

API Threat Model

Security platform

API Threat ModelWorkspace5 updates
API Threat Model · Authorisation Reviewendpoints with no authorisation finding
2 critical

Broken object-level authorisation is the first thing worth looking for in any API, because it needs no exploit: change the id in the URL and the server hands over someone else's record. Each endpoint here is checked for object-level and function-level authorisation, mass assignment, unauthenticated writes, and unbounded auth paths.

Endpoints

6

in the inventory

Critical

2

fix before ship

BOLA exposures

2

client id, no ownership check

Clean

1

no finding

Clean endpoints6 inventoried
1/6clean
Control coverage across the surface
Authenticated4/6Ownership check2/6Role check2/6Rate limited3/6

Authentication is nearly universal and ownership checks are not, which is exactly the shape that produces BOLA. Knowing who is calling is not knowing what they may address.

2 endpoints accept a client-supplied object id with no server-side ownership check. No exploit is needed: change the id in the URL.

Endpoint findings
GET/api/invoices/:idsession

API1 BOLAAccepts an object id from the client with no server-side ownership check

Fix: Scope the query by the authenticated subject: select where id = :id and owner_id = :caller. Never trust the id alone.

API3 excessive exposureReturns personal data with no rate limit, so enumeration is cheap

Fix: Rate limit, and return only the fields the client renders rather than the whole record.

PATCH/api/users/:idsessionowns check

API6 mass assignmentBinds the whole request body to the model, so a caller can set fields like role or tenant_id

Fix: Validate against an allow-list schema that names exactly the writable fields, and never spread the body into the update.

API3 excessive exposureReturns personal data with no rate limit, so enumeration is cheap

Fix: Rate limit, and return only the fields the client renders rather than the whole record.

POST/api/auth/loginno auth

API4 unrestricted consumptionAuthentication endpoint with no rate limit or backoff

Fix: Rate limit per account and per source, with exponential backoff and a generic failure message so it is not an enumeration oracle.

DELETE/api/admin/tenants/:idsessionrole checkrate limited

API1 BOLAAccepts an object id from the client with no server-side ownership check

Fix: Scope the query by the authenticated subject: select where id = :id and owner_id = :caller. Never trust the id alone.

GET/api/reports/exportapiKeyowns checkrole checkrate limited

No finding: authenticated, authorised at object and function level, rate limited

POST/api/webhooks/stripeno authrate limited

API2 broken authenticationUnauthenticated write endpoint: signature verification is the only control

Fix: Verify the provider signature over the raw body before parsing, and reject stale timestamps to stop replay.

Zain Khalil Khan