IDOR in the Wild
Why insecure direct object references still pay bounties — and where to look in 2026.
An IDOR is not a clever bug. It is the absence of one specific check, in one specific handler, on one specific endpoint. Companies ship them constantly because authorization is harder than authentication, and it scales worse.
What IDOR actually is
The textbook definition — "an attacker changes an ID in a URL and accesses someone else's data" — is correct but small. The real definition: the application accepts an identifier from the client and returns or modifies the corresponding resource without checking that the current user is allowed to interact with it.
The identifier might be in:
- A URL path:
/api/invoices/4821 - A query string:
?file_id=4821 - A request body:
{"target_user": 4821} - A header:
X-Account-Id: 4821 - A cookie, occasionally — and those are gold when you find them.
- A websocket frame.
- A GraphQL query argument.
"UUIDs make this safe" is a myth. UUIDs only make the bug harder to find by enumeration. They do nothing about the underlying authorization gap. If you can leak, share, or reference a UUID anywhere — invitations, public profiles, support tickets, share links — the bug is still there.
The methodology that keeps paying
Every productive IDOR session I've ever had follows roughly the same loop:
- Map the resource model. What objects does the app have? Users, projects, files, messages, invoices, comments, drafts, exports. For each, find the create / read / update / delete endpoints.
- Use two accounts. Always. Account A creates resources. Account B, in a different browser profile, tries to access them by ID.
- Test every HTTP verb. GET might be locked down. PUT, PATCH, and DELETE on the same path frequently are not — different developers, different decade, different review.
- Test every related action. If you can't read an object, can you share it? Export it? Add a collaborator to it? Comment on it? Each side action is a separate authorization decision.
- Look for "force browse" via UI traversal. The app navigates from project → file. Skip the project step. Hit the file endpoint directly with an ID you guessed.
Higher-order IDOR patterns
Once you've cleared the obvious cases, the bigger bounties live in second-order issues:
Mass assignment
PATCH /api/users/me
{ "email": "new@x.com", "role": "admin", "tenant_id": 99 }
The endpoint expects you to update your email. The serializer accepts whatever you throw at it. Suddenly you've changed your role, or moved your account into someone else's tenant. This is IDOR-adjacent and deeply rewarding.
Stale references
You were a member of a project, then removed. Does your old API token still work against that project's endpoints? Often yes. Token-bound vs. membership-bound permission checks are commonly inconsistent.
Indirect references
Some apps replaced numeric IDs with "secure" tokens — but the token is just base64(user_id + ":" + invoice_id). Decode every opaque identifier you encounter. The number of times this works is embarrassing to the industry.
GraphQL nesting
GraphQL frequently has authorization on root queries but not on nested fields. viewer { otherUsers(id: 4821) { email } }-style queries are an entire sub-genre. Test every relation; do not assume the field-level resolver checks anything.
Bulk endpoints
Per-item auth is implemented; bulk-action endpoints frequently are not. POST /api/files/bulk-delete with a body containing files you don't own is a classic.
Why companies still ship them
Authorization is contextual in a way authentication is not. "Is this person logged in?" has one answer. "Is this person allowed to do this to that?" depends on the resource type, the relationship between user and resource, the current state of both, and any number of business rules.
That contextual nature means authorization checks have to be re-implemented for every new feature, by whichever engineer happens to be writing it. Frameworks help — policy systems, ABAC libraries, row-level-security in the database — but only if used consistently. They almost never are.
That gap is your job security as a hunter. Be patient, be systematic, and keep two accounts logged in side by side. The bugs are still there.