Skip to content

IDOR in Your API

IDOR in your API is an object-level authorisation bug where an endpoint accepts an identifier, loads the referenced record, and returns or changes it without checking that the caller may access that specific record. The identifier is only the handle; the missing ownership or scope check is the vulnerability.

APIs often need direct references to resources: project ids, invoice ids, user ids, file ids. That is normal. The danger appears when the server authenticates the caller, then assumes any valid id they send is fair game. An attacker does not need to break login or exploit memory corruption. They can change a path parameter, request body field, or GraphQL argument and see whether another user’s object comes back.

A safe endpoint answers two questions as one operation: which object is being requested, and is it inside the caller’s permitted scope? In practice that means querying with both the object id and an ownership constraint, such as the caller’s organisation, tenant, account, membership, or sharing rule. The unsafe shape is easy to recognise: load by primary key, then serialize or mutate the result while only checking that a user is logged in.

Generated CRUD code commonly creates this bug because it knows database structure better than business authority. It can scaffold routes, controllers, serializers, and basic authentication around table ids, but it cannot infer whether a record belongs to a creator, an organisation, a parent account, a shared workspace, or a role-specific workflow. The trade-off is speed of development versus forcing every generated handler to be wrapped in explicit object-level authorisation.

Engineers meet IDOR during route review, controller review, resolver review, and service-layer review. Search for parameters named like ids, calls that fetch a model by primary key, and update or delete methods that accept ids from the request. The honest test is not whether ids are hard to guess. It is whether the code still denies access when a real id for someone else’s object is supplied.

Common questions

Is IDOR fixed by using UUIDs instead of sequential ids?
No. UUIDs can make casual discovery harder, but they do not prove authorisation. If a user obtains a UUID through logs, browser state, search results, an invitation, or another endpoint, the same broken access check remains. Treat unguessable ids as a minor defence, not as a permission model.
Where should the ownership check live?
It depends on the architecture, but it must be unavoidable. Many teams enforce scope in repository queries or service methods, so callers cannot accidentally fetch unrestricted objects. Controller-only checks are easier to miss. The key property is that every read, update, and delete path applies the same object-level rule.
How do I spot IDORs in an existing codebase?
Start with endpoints that accept an id from the client. Follow the value into ORM calls, query builders, service methods, and resolvers. Flag code that fetches by id alone, then returns, updates, or deletes the object. Then verify whether later logic checks organisation, tenant, membership, owner, sharing, or role constraints before acting.