Glossary
Access control

What is Insecure Direct Object Reference?

Also calledIDORBroken object level authorizationBOLA

Definition

An insecure direct object reference is an access control failure in which an application uses a user-supplied identifier to select a record and does not check that the requesting user is allowed to see that particular record.

What an insecure direct object reference is

The application knows who you are. It checked your session, and the check passed. Then it reads an identifier out of the request, looks up the record with that identifier, and returns it. The step it skipped is the one that asks whether this user is entitled to this record. That is the entire bug, and it is the most reported class in bug bounty programmes for a reason: it survives every framework, every language, and every code review that only looks for injection.

The API-focused naming, broken object level authorization, is more precise and worth preferring in a report, because it names the missing control rather than the visible symptom. The identifier being guessable is not the vulnerability. It only decides how expensive exploitation is.

Why replacing the identifier is not a fix

Swapping a sequential integer for a UUID is the most common response and the least effective one. It raises the cost of enumeration and changes nothing about the missing check. Identifiers leak constantly: in shared links, in exports, in referrer headers, in support tickets, in the very list endpoint that returned them to a user who was allowed to see one of them. A control whose strength depends on an identifier staying secret is not an access control, it is an obscurity budget, and the audit will say so.

How to find it reliably

  1. Get two accounts. Ideally in two different tenants, otherwise two users in one tenant. Almost every reliable finding in this class comes from a side-by-side comparison rather than from a single trace.
  2. Record a full session as account A, then replay each request with account B credentials and account A identifiers.
  3. Read the difference between 403 and 404 carefully. A consistent 404 for both non-existent and unauthorised records is correct behaviour. A 403 for one and a 404 for the other is an enumeration oracle and a separate, lower-severity finding.
  4. Check the write paths as well as the read paths. Applications frequently authorise a GET properly and forget the PATCH.
  5. Check nested and indirect references: an identifier inside a JSON body, inside a batch request, inside an export job specification.

What actually fixes it

Scope the query to the actor rather than checking after the fact. A lookup written as "find this record where the owner is the current user" cannot return a record the user is not entitled to, whereas "find this record, then check the owner" is a control someone can forget to add to the next endpoint. Making the scoped form the only convenient way to query, at the data access layer, is what turns this from a per-endpoint discipline into a property of the codebase.

Worked example

What it looks like in practice

two-account-comparison.sh
# Two accounts, one identifier. The whole method in four lines.
# Run only against a system you have permission to test.

A_TOKEN="<session token for account A>"
B_TOKEN="<session token for account B, different tenant>"
RECORD="inv_01J8Z2K9QW"   # an identifier account A is entitled to

# Baseline: A reading A's own record. Expect 200.
curl -s -o /dev/null -w '%{http_code}\n' \
  -H "Authorization: Bearer $A_TOKEN" \
  "https://app.example.com/api/v2/invoices/$RECORD"

# The test: B reading A's record. Expect 404. A 200 is the finding.
curl -s -o /dev/null -w '%{http_code}\n' \
  -H "Authorization: Bearer $B_TOKEN" \
  "https://app.example.com/api/v2/invoices/$RECORD"
The comparison that produces the finding. Note the expected result is 404 rather than 403: a 403 confirms the record exists, which is a smaller but separate issue.
Commonly confused with

What it is not

The distinction matters more than the definition does, because these are the terms people swap by accident in a report.

Flashcards

5 cards

Tap a card to reveal the answer. Answers are in the page source, so this works with JavaScript disabled.

  • What is the missing control in an IDOR?

    An object-level authorisation check. The application authenticates the user and then selects a record by a user-supplied identifier without asking whether that user is entitled to that record.

  • Why does switching from sequential IDs to UUIDs not fix an IDOR?

    It raises the cost of enumeration and leaves the missing check in place. Identifiers leak through links, exports, referrers and list endpoints, so secrecy is not an access control.

  • What is the difference between a 403 and a 404 on an unowned record?

    A 404 for both unauthorised and non-existent records reveals nothing. A 403 for one and 404 for the other confirms which records exist, which is an enumeration oracle and a separate lower-severity finding.

  • What is the durable fix at the code level?

    Scope the query to the actor: select the record where the owner is the current user, so an unauthorised record cannot be returned, rather than fetching first and checking afterwards.

  • Why is two accounts the core of the testing method?

    The bug only becomes visible in the difference between two sessions. One trace shows an application working correctly; the side-by-side replay shows the missing check.

Instructor note

Where people get this wrong

The reports that get closed are the ones written about the identifier. The reports that get paid are written about the records. Learners spend a lot of energy proving that an identifier is predictable and almost none proving how many records the flaw reaches, which is the number a triager needs in order to assign a severity. Test it with two accounts, state the reachable set, and stop talking about the format of the identifier entirely.
Cyber VK Security Curriculum, Pre-publication content owner
Practise it

Where you can use this

The G1 gate for this template: the artifacts below exist nowhere else in this combination.

Cyber VK Security Curriculum

Pre-publication content owner

Internal ownership label for the web-security curriculum.

Technically reviewed by Cyber VK Defensive Research

Updated

All glossary terms

What Is Insecure Direct Object Reference? Definition and Example