What Is IDOR? Insecure Direct Object References Explained
IDOR is an access control flaw where an app trusts a user-supplied ID to fetch a record without checking the requester actually owns it.
IDOR, short for Insecure Direct Object Reference, is an access control vulnerability where an application uses a user-supplied identifier — an ID in a URL, form field, or API request — to fetch a record, without verifying that the requester is actually authorized to access that specific record. The classic example: GET /api/invoices/1042 returns your invoice, but changing the URL to GET /api/invoices/1043 returns someone else’s, because the server checked that an invoice with that ID exists but never checked that it belongs to the requester.
The vulnerability, minimally
IDOR isn’t a bug in encryption, input sanitization, or a memorable exploit chain — it’s a missing if. A typical vulnerable handler looks something like:
GET /api/orders/:orderId
order = db.orders.find(orderId)
return order
The endpoint correctly authenticates the request (the caller is logged in) but never checks authorization — whether the logged-in user is allowed to see this particular order. Authentication answers “who are you”; authorization answers “are you allowed to do this.” IDOR is what happens when a system does the first check and skips the second. The fix is almost always as small as the bug:
GET /api/orders/:orderId
order = db.orders.find(orderId)
if order.userId != currentUser.id: return 403
return order
Why it’s so common
IDOR sits on the OWASP Top 10 as part of the broken access control category, consistently one of the most reported classes of vulnerability in web applications. It’s common for a few structural reasons:
- It’s invisible in normal testing. The endpoint works perfectly when you test it with your own account and your own IDs. The bug only appears when someone tries an ID that isn’t theirs — which automated functional tests rarely do.
- Sequential and guessable IDs make it trivial to exploit. Auto-incrementing integer primary keys mean an attacker can enumerate
?id=1,?id=2,?id=3and harvest records without any special tooling. - It scales across every resource type independently. A codebase can correctly enforce ownership checks on orders but miss them on shipping addresses, support tickets, or exported reports — each endpoint needs its own check, and one miss is enough.
- It often survives code review. The code reads as correct — it fetches a record and returns it — unless the reviewer is specifically looking for the missing ownership check.
IDOR vs related access control flaws
| IDOR | CSRF | SSRF | |
|---|---|---|---|
| What fails | Object-level authorization | Origin verification of a request | Server-side URL trust |
| Attacker needs | A valid ID to substitute | A victim to visit a malicious page | An input field that accepts a URL |
| Typical fix | Ownership check per resource | Anti-forgery tokens, SameSite cookies | URL allowlisting, blocking internal ranges |
| Where it lives | Application authorization logic | Session/cookie handling | Server-side request logic |
IDOR is also distinct from broken authentication — a user exploiting IDOR is fully, legitimately logged in as themselves. See CSRF and SSRF for how those adjacent flaws differ in mechanism.
Where IDOR shows up beyond URLs
The pattern isn’t limited to REST path parameters. Any place a client supplies an identifier that the server trusts without an ownership check is a candidate:
- Query parameters and request bodies (
{"userId": 4821}in a PATCH request) - File paths and download endpoints (
/files/download?name=report-4821.pdf) - GraphQL resolvers that fetch by node ID without a permission check in the resolver itself
- Bulk or batch endpoints that accept an array of IDs — often the ownership check gets applied to the first ID and forgotten for the rest
- API responses that leak internal IDs in one place, which then work as valid input elsewhere in the same API
Preventing IDOR systematically
Point fixes on individual endpoints don’t scale — the goal is to make the missing check the exception, not something engineers have to remember on every route.
- Enforce authorization centrally. Middleware or a policy layer that runs an ownership or permission check before a handler touches the database, rather than trusting each handler to remember it. RBAC or ABAC models formalize what “authorized” means so the check is consistent across resource types.
- Prefer indirect references. Instead of exposing raw database primary keys, use per-user or per-session opaque tokens that map to the real record server-side. This doesn’t replace authorization checks, but it removes the trivial enumeration attack.
- Use non-sequential identifiers. UUIDs don’t fix IDOR — the authorization check still has to exist — but they remove the “just increment the number” shortcut that makes exploitation nearly automatic.
- Test for it deliberately. Functional tests confirm a user can access their own data; authorization tests confirm they can’t access someone else’s. The second kind needs to be written on purpose — nothing about normal testing produces it. This is exactly the class of flaw dynamic application security testing is well suited to catch, since it needs a live request with a substituted ID rather than static code inspection alone.
The takeaway
IDOR is what happens when an application checks that you’re logged in but never checks that the specific record you’re asking for is yours. It requires no special exploit tooling — just substituting an ID — which is exactly why it’s stayed near the top of real-world vulnerability reports for years. The fix is a per-resource ownership check, ideally enforced centrally rather than left to each handler to remember, plus opaque or non-sequential identifiers to raise the cost of blind enumeration.
Keep reading
Chisato · · 5 min read What Is Session Fixation?
Session fixation tricks a victim into using an attacker-known session ID, so logging in hands the attacker an authenticated session too.
Chisato · · 4 min read The OAuth PKCE Flow Explained
PKCE hardens the OAuth authorization code flow against interception, and is now recommended for every client type, not just mobile and single-page apps.
Chisato · · 4 min read Cookie Attributes Explained: HttpOnly, Secure, SameSite
HttpOnly, Secure, and SameSite are cookie attributes that block script access, force HTTPS, and limit cross-site sending. Here's what each one actually stops.