What Is IDOR ?Why Should You Care?

Imagine you receive a receipt after buying coffee. The receipt is numbered #103. Now imagine you walk up to the counter and say, "Can I see receipt #101?" — and the cashier hands it over, no questions asked. You now know what a stranger ordered, when they paid, and which card they used. That is IDOR — Insecure Direct Object Reference. It happens when an application uses a user-supplied identifier (a number, filename, or key) to fetch an object directly from the backend, without verifying whether the requesting user is actually authorized to access it.

In the context of APIs, IDOR is ranked under OWASP API Security Top 10 as API1: Broken Object Level Authorization (BOLA), the single most common and most exploited API vulnerability. The reason it sits at #1 is its devastating simplicity: exploitation often requires nothing more than changing a single value in a request.

How IDOR Occurs in APIs

APIs are fundamentally built around resources and identifiers. A typical API request looks like this: GET /api/users/47/profile

Authorization: Bearer <token

The server receives the request, sees 47, and returns that user's profile. The critical question is: does the server check whether the authenticated user has permission to view user 47's data, or does it blindly trust the ID in the URL? IDOR occurs when the answer is the latter.

There are three common patterns where IDOR surfaces in APIs:

1. Direct References to Database Objects

The most classic form. API endpoints expose internal database IDs — usually sequential integers — as part of the URL path or query parameters:

GET /api/orders/1024

GET /api/invoices?id=55

If the server resolves these IDs directly to database rows without an authorization check, any authenticated user can enumerate other users' records by simply incrementing or decrementing the ID.

2. Direct References to Static Files

Sometimes applications store user-generated content: documents, transcripts, reports as static files on the server, named with predictable identifiers. A request to download such a file might look like:

GET /download-transcript/3.txt

The filename 3.txt acts as the direct reference. If there is no access control verifying that the requesting user owns transcript #3, then any user can request 1.txt, 2.txt, or any other file, gaining access to other users' private data.

3. References in Request Bodies or Parameters

IDOR is not limited to URL paths. It can appear in POST bodies, query strings, headers, or any parameter the client controls:

```json
POST /api/transfer
{
  "from_account": "ACC-4421",
  "to_account": "ACC-8890",
  "amount": 500
 }

If the server does not verify that the authenticated user owns ACC-4421, an attacker can initiate transfers from arbitrary accounts.

The Attacker Mindset: What a Tester Looks For

An API pen-tester does not approach an application by randomly firing payloads. IDOR testing is methodical, and it begins with a simple question: "Where does this application let me reference an object by ID, and can I reference someone else's?"

Step 1: Map Every Identifier

The first task is identifying every place the API uses an object reference. The tester proxies all traffic through a tool like Burp Suite, interacts with the application normally, and catalogs every request that contains an ID, filename, key, or reference of any kind. This includes:

  • URL path parameters (/users/5, /download/3.txt)
  • Query parameters (?order_id=201)
  • Request body fields ("account_id": "A-100")
  • Cookie values or custom headers that carry references

To illustrate this, I completed a lab-based scenario modeled on a controlled PortSwigger exercise.

The Application

A web application features an AI-powered customer support chatbot.

None

Step 2: Create Two Accounts

IDOR testing fundamentally requires two separate users with distinct data. The tester logs in as User A, performs actions that generate data (places an order, creates a file, starts a chat), and records the identifiers associated with that data. Then they do the same as User B.

The test is straightforward: using User B's session, attempt to access User A's objects.

For my lab context, there already existed another users actions on the App. So I went in straight to chat to complete the second user's actions on the lab.

Start a chat with the bot.

None

Step 3: Swap the Identifier

This is the core of the test. In Burp Suite's Repeater tool, the tester takes a legitimate request from User B and replaces User B's object identifier with User A's. If the server returns User A's data, the IDOR is confirmed.

In my simple demo lab, after a conversation, users can click "View Transcript" to review and download their chat history as a text file.

For example, suppose User B downloads their own chat transcript:

None

The Observation: After clicking "View Transcript," Burp Suite captures the following request:

GET /download-transcript/2.txt HTTP/2
Host: 0aca00ab03d447bd848ef9b800910093.web-security-academy.net
Cookie: session=o4qMoOs71yPyHpKg67U84beJTF0n7Sab

The server responds with User B's chat history. This is a legitimate action.

The tester then changes the filename

The Test: The tester modifies the request in Burp Suite's Repeater, changing the filename from 2.txt to 1.txt

None
GET /download-transcript/1.txt HTTP/2
Host: 0aca00ab03d447bd848ef9b800910093.web-security-academy.net
Cookie: session=o4qMoOs71yPyHpKg67U84beJTF0n7Sab

The Result: The server responds with a completely different user's chat transcript using User B's session cookie, which should only authorize access to User B's data. The vulnerability is confirmed. The session cookie authenticated who the user is, but the server never checked whether that user was authorized to access file 1.txt.

Step 4: Assess Predictability

The severity of an IDOR depends partly on how predictable the identifiers are. Sequential integers (1, 2, 3) are trivially enumerable, an attacker can write a script to download every record in the database. UUIDs are harder to guess but are not a defense on their own; they may leak in other API responses, logs, or URL parameters. A tester asks: "Can I enumerate these? Can I find them elsewhere in the application?"

A single modified character in the request — changing 2 to 1 and exposed another user's private conversation, which in this case contained their plaintext password. The session cookie authenticated the tester as a valid user of the application, but the server never verified whether that user was authorized to access transcript 1.txt.

What made this possible

The file references were sequential integers, making enumeration trivial. The server performed authentication (verifying the session cookie was valid) but not authorization (verifying the user owned the requested file).

Sensitive data was stored in the transcript with no additional protection.

The Impact: Why IDOR Matters

IDOR is not a theoretical concern. When exploited in production systems, the consequences are severe:

  • Data Breach at Scale. Because IDOR identifiers are often sequential, exploitation is trivially automatable. An attacker can write a loop that requests /api/users/1 through /api/users/100000 and harvest every user's data in minutes. This is not a single-record leak but a full database extraction through the front door.
  • Account Takeover. As the lab demonstrated, leaked data may include credentials, password reset tokens, or session identifiers. An IDOR that exposes a chat transcript containing a password directly enables account takeover the attacker does not need to crack or brute-force anything.
Hal Pline: Takes one to know one
You: Ok so my password is kzjeqp1746za7qptusv3. Is that right?
Hal Pline: Yes it is!
None
None
  • Privilege Escalation. IDOR can expose administrative objects (configuration records, role assignments, internal reports) to regular users, enabling vertical privilege escalation without exploiting any authentication flaw.
  • Regulatory and Legal Consequences. Unauthorized access to personal data triggers obligations under GDPR, HIPAA, PCI-DSS, and similar frameworks. An IDOR leading to mass data exposure can result in mandatory breach notifications, regulatory fines, and litigation.

Why APIs Are Especially Vulnerable to IDOR

IDOR exists in traditional web applications too, but APIs are disproportionately affected for several structural reasons:

  • APIs expose raw identifiers by design. A web application might obscure an order ID behind a "View Order" button. An API endpoint explicitly puts it in the URL: GET /api/orders/1024. The identifier is not hidden, it is the interface.
  • No server-side rendering to mask data. In a traditional web app, the server can render only the data the current user should see. An API returns the full data object, trusting the client to display it appropriately. If authorization is missing, the API simply hands over everything.
  • Client-side enforcement is not enforcement. Many developers implement access control in the frontend, only showing the "View Transcript" button for the user's own transcripts. But the API endpoint /download-transcript/2.txt exists independently of the UI. An attacker bypasses the frontend entirely and talks directly to the API.
  • Microservice architectures fragment authorization. In monolithic applications, a single auth layer can enforce access control globally. In microservice architectures, each service must independently verify authorization. If the transcript service trusts that the API gateway already checked permissions but the gateway only checked authentication and IDOR is the result.

How Developers Can Prevent IDOR

IDOR is fundamentally an authorization failure, and the fix is authorization enforcement. Here are concrete measures:

  1. Enforce Object-Level Authorization on Every Request Every API endpoint that returns or modifies a resource must verify that the authenticated user is authorized to access that specific resource. This check must happen server-side, on every request, regardless of how the user reached the endpoint.
# Pseudocode — every resource access must include this check
def get_transcript(request, file_id):
 transcript = db.get_transcript(file_id)
 if transcript.owner_id != request.authenticated_user.id:
 return 403_Forbidden
 return transcript
```

2. Use Indirect References

Instead of exposing database IDs or filenames directly, map each user's resources to session-specific references. The user sees "Transcript 1" which maps internally to their specific file not to a global 1.txt.

3. Replace Sequential IDs With UUIDs

While not a fix on their own, UUIDs (a3f8b2c1-7d4e-4f5a-9b2c-1e3d5f7a9b2c) make enumeration impractical. An attacker cannot guess the next UUID the way they can guess that 1.txt is followed by2.txt. This is defense-in-depth, not a substitute for authorization checks.

4. Implement Automated Authorization Testing

Manual testing does not scale. Integrate authorization tests into the CI/CD pipeline that specifically test cross-user access: "Can User B's token access User A's resources?" These tests catch IDOR regressions before they reach production.

5. Centralize Authorization Logic

Avoid scattering authorization checks across individual endpoints. Use middle-ware or a policy engine that enforces object-level access control consistently across all endpoints, reducing the chance that a single endpoint is missed.

Conclusion

This lab demonstrates how a simple change to an object reference can expose deep authorization flaws in APIs.

The vulnerability was not caused by lack of authentication. It was caused by missing object-level authorization enforcement.

IDOR vulnerabilities are dangerous because they require no advanced exploitation. They exploit logic, not memory corruption.

Thinking like an attacker means asking:

"If I can see mine, can I see yours?"

In API security, that question alone can uncover critical flaws.