Services Cases About Blog Contact Request diagnostic
Real case · IDOR/BOLA

IDOR: why "only the owner can see it" has to be enforced on the backend, not the frontend

IDOR: why

What IDOR is

IDOR stands for Insecure Direct Object Reference, also called BOLA (Broken Object Level Authorization) when it's an API. In practice: the system identifies a resource (an order, a contract, a file) by an ID, and some route returns or modifies that resource just by checking that the ID exists, without checking whether it belongs to whoever is asking.

It's probably the most common flaw, and the cheapest to fix, in any multi-tenant SaaS or marketplace. It's also one of the easiest to exploit: often all it takes is swapping a number in the URL or request body.

The case

On a B2B marketplace, a route that returned order details accepted the order ID directly in the request, and returned the data without checking whether that order belonged to the authenticated company. By swapping the ID for another sequential value, it was possible to view other clients' orders: purchased items, negotiated prices, contact details.

It didn't take a sophisticated tool or a complex exploit. It just took someone trying an ID that wasn't theirs, and noticing that the system responded anyway.

Why this happens so often

Usually because the ownership check exists on the frontend (the menu only shows the user's own orders) but doesn't exist again on the backend, on the route that actually returns the data. The frontend is never a security boundary: any request can be replayed directly against the API, bypassing the entire interface.

The root cause is almost always the same: the backend trusts the ID that came in the request, instead of comparing that ID against what the authentication token actually authorizes.

How to prevent it

  • Every route that receives a resource ID needs to verify, on the backend, that the resource belongs to the authenticated user or tenant, never trusting the ID's mere existence.
  • The tenant or user ID used for that check comes from the signed session token, never from a field the client sends in the request.
  • Deliberately test by swapping resource IDs during development, not only after the system is already in production.

It's a simple fix to implement. The hard part is remembering to apply that check on every new route someone writes, months after the original pattern was set, which is exactly the kind of thing a recurring pentest catches before it turns into an incident.

Does your API check resource ownership on every single route?

Request an API Pentest
← Back to blog