Skip to content
Knowledge Base

IDOR — What Is Insecure Direct Object Reference and How to Prevent It

IDOR (Insecure Direct Object Reference) is a critical access control vulnerability that exposes private data through predictable object identifiers. Learn how IDOR works, real-world attack examples, and proven prevention techniques.

Access control vulnerabilities consistently rank as the most critical risk in web application security. Among them, IDOR (Insecure Direct Object Reference) stands out as one of the most common, most easily exploitable, and most frequently overlooked. An attacker does not need sophisticated tools or deep technical knowledge to exploit an IDOR vulnerability — in many cases, changing a single number in a URL is enough to access another user’s private data.

This article provides a comprehensive examination of IDOR — how it works, why it persists in modern applications, how to detect it through testing, and how to eliminate it through proper architectural decisions. Whether you build web applications, test them for security, or manage the infrastructure they run on, understanding IDOR is essential.

What Is IDOR?

IDOR (Insecure Direct Object Reference) is a type of access control vulnerability that occurs when an application exposes a direct reference to an internal implementation object — such as a database record, file, or directory — and fails to verify whether the requesting user is authorized to access that specific object.

The term was popularized by OWASP (Open Web Application Security Project), which originally listed IDOR as a standalone category in its Top 10. In the OWASP Top 10 2021, IDOR falls under A01:2021 — Broken Access Control, which climbed to the number one position from fifth place in the previous edition. This promotion reflects the reality that access control failures, including IDOR, have become the most widespread and dangerous class of web application vulnerabilities.

At its core, IDOR is not a complex vulnerability. It follows a straightforward pattern:

  1. The application uses a direct identifier (like an integer ID) to reference objects.
  2. The user can see and manipulate this identifier in URLs, form parameters, or API requests.
  3. The server processes the request using the provided identifier without checking whether the authenticated user has permission to access the referenced object.

The simplicity of this pattern is precisely what makes IDOR so dangerous — it is easy to introduce during development and easy to exploit in production.

How IDOR Works

To understand how IDOR vulnerabilities arise and are exploited, consider a typical web application that manages user profiles. When a user views their own profile, the application might generate a request like:

GET /api/users/1847/profile

The number 1847 is a direct reference to the user’s record in the database. If the server-side handler for this endpoint retrieves the profile data based solely on the ID in the URL — without verifying that the authenticated session belongs to user 1847 — then any authenticated user can access any profile by simply changing the number:

GET /api/users/1/profile
GET /api/users/1848/profile
GET /api/users/9999/profile

This is the fundamental IDOR pattern. Let us examine its variations and escalation paths in detail.

Predictable Identifiers

The most common IDOR scenarios involve sequential integer IDs. When a database uses auto-incrementing primary keys and the application exposes these keys to users, the entire set of valid identifiers becomes trivially enumerable. An attacker who knows their own ID is 1847 can reasonably assume that IDs 1 through 1846 belong to other users and iterate through all of them programmatically.

But predictable identifiers extend beyond simple integers. Timestamps, date-based references (invoice-2026-04-0001), and even some poorly implemented hash functions produce guessable values. Any identifier an attacker can predict or enumerate without authorization constitutes a potential IDOR vector.

Horizontal Privilege Escalation

Horizontal privilege escalation occurs when an attacker accesses resources belonging to another user at the same privilege level. This is the most common form of IDOR exploitation. Examples include:

  • Viewing another user’s orders: GET /api/orders/5291 returns order details for a different customer
  • Downloading another user’s documents: GET /documents/download?id=8832 serves a file uploaded by someone else
  • Reading private messages: GET /api/messages/conversation/441 exposes a conversation between two other users

In each case, the attacker does not gain elevated privileges — they simply access data that belongs to a peer. The impact is a breach of data confidentiality, which can range from embarrassing (viewing another person’s profile settings) to catastrophic (accessing financial records, medical data, or legal documents).

Vertical Privilege Escalation

Vertical privilege escalation through IDOR is less common but far more dangerous. It occurs when manipulating an object reference grants the attacker access to resources reserved for users with higher privileges. Scenarios include:

  • Accessing admin endpoints: GET /api/admin/users/list returns all user records when called with a regular user’s session token
  • Modifying role assignments: PUT /api/users/1847 with a request body containing {"role": "admin"} elevates the attacker’s own privileges
  • Viewing system configuration: GET /api/settings/global returns sensitive application settings not intended for regular users

Vertical IDOR often results from inconsistent authorization — the application checks permissions for some endpoints but not others, or checks the user’s role at the page level but not at the API level.

IDOR Attack Examples

The following examples illustrate how IDOR manifests across different application components and data types.

Example 1: E-Commerce Order History

A customer views their order at https://shop.example.com/orders/10432. The page displays order details including items purchased, shipping address, payment method (last four digits), and delivery status. By changing the order ID to 10431, the attacker sees another customer’s complete order — including their home address and partial payment information. An automated script iterating from 1 to 10432 extracts the entire customer order database.

Example 2: File Download via Path Manipulation

A document management system provides download links in the format:

GET /api/files/download?path=/users/john.smith/contracts/employment.pdf

An attacker modifies the path parameter to:

GET /api/files/download?path=/users/jane.doe/contracts/employment.pdf

If the server resolves the path without verifying ownership, the attacker obtains another employee’s employment contract. This variant combines IDOR with path traversal — an attacker might also try ../../admin/config.yml to access system files.

Example 3: Account Settings Modification

A banking application’s profile update endpoint accepts:

PUT /api/accounts/7721
Content-Type: application/json

{"email": "attacker@evil.com", "phone": "+1-555-0199"}

If the server updates account 7721 based on the URL parameter without checking that the authenticated user owns that account, the attacker can change another customer’s email and phone number — the first step toward a full account takeover through the password reset flow.

Example 4: Bulk Data Extraction via API Pagination

A SaaS application’s API returns user data in paginated form:

GET /api/v2/workspace/reports?user_id=4821&page=1&per_page=50

An attacker writes a script that iterates user_id from 1 to 100000, collecting all reports from every user in the system. Because the API only checks whether the caller is authenticated (has a valid token) but not whether they are authorized to access the specified user’s data, the entire dataset is exfiltrated.

Real-World IDOR Incidents

IDOR vulnerabilities have affected organizations of all sizes, from startups to enterprises handling millions of users.

Social Media Platform Exposures

Multiple major social media platforms have disclosed IDOR vulnerabilities through bug bounty programs. In these cases, attackers could access private user data — including unpublished posts, friend lists, and account settings — by manipulating numeric user IDs in API calls. The common thread was the use of sequential user IDs combined with API endpoints that checked authentication but not authorization.

Financial Services Data Leaks

Banking and fintech applications have experienced IDOR vulnerabilities that exposed account balances, transaction histories, and personal identification documents. In one notable case, a researcher discovered that changing the account number in an API request returned other customers’ bank statements as downloadable PDFs. The vulnerability existed because the PDF generation service received the account number as a parameter and trusted it without re-validating the caller’s identity.

Healthcare Record Breaches

Healthcare portals have been particularly susceptible to IDOR, with vulnerabilities exposing patient records, lab results, and prescription histories. The severity of these breaches is amplified by regulatory frameworks like HIPAA, which impose significant penalties for unauthorized disclosure of protected health information. In several documented cases, patient portal URLs contained sequential appointment IDs that, when modified, revealed other patients’ medical records.

Government Portal Vulnerabilities

Government web portals — including tax filing systems, benefits applications, and voter registration databases — have experienced IDOR vulnerabilities that exposed citizens’ personal data. These cases are particularly concerning because government systems often contain Social Security numbers, tax records, and other data that enables identity theft.

Testing for IDOR

Detecting IDOR requires systematic testing that goes beyond automated scanning. While vulnerability scanners can identify some access control issues, IDOR testing fundamentally requires understanding the application’s authorization model and manually crafting requests to test its boundaries.

Manual Testing Methodology

A structured approach to IDOR testing follows these steps:

  1. Map the application: Identify all endpoints that reference objects by ID, filename, or other identifiers. Pay special attention to URLs, form hidden fields, API parameters, and cookie values.

  2. Create test accounts: Set up at least two accounts with different roles and data. For example, User A (regular user with orders 1-5) and User B (regular user with orders 6-10), plus an admin account.

  3. Capture baseline requests: Using a proxy like Burp Suite, interact with the application as User A and record every request that contains an object reference.

  4. Replay with different context: Take each captured request and replay it using User B’s session. If User B can access User A’s objects, IDOR exists.

  5. Test boundary conditions: Try accessing objects with IDs of 0, negative numbers, very large numbers, and non-numeric values. Test with no authentication, expired sessions, and different content types.

  6. Document and verify: For each finding, document the exact request, the expected behavior (403 Forbidden or 404 Not Found), and the actual behavior (200 OK with another user’s data).

Burp Suite for IDOR Testing

Burp Suite is the industry standard tool for IDOR testing. Key features include:

  • Proxy: Intercepts and modifies requests in real-time, allowing you to change object IDs before they reach the server
  • Repeater: Replays individual requests with modifications, ideal for testing specific endpoints
  • Intruder: Automates parameter fuzzing by iterating through ranges of IDs
  • Autorize extension: The most powerful tool for systematic IDOR testing — it automatically replays every request captured from a privileged session using a lower-privileged session and highlights discrepancies

A typical Autorize workflow: configure two sessions (privileged and unprivileged), browse the application using the privileged session, and Autorize automatically replays every request with the unprivileged session’s cookies. Any response that returns 200 instead of 403 is a potential IDOR finding.

Automated Scanning Limitations

Traditional DAST (Dynamic Application Security Testing) tools struggle with IDOR because:

  • They cannot understand business logic (whether User A should access Object X)
  • They typically test with a single session, so horizontal privilege escalation goes undetected
  • They focus on technical vulnerabilities (XSS, SQLi) rather than authorization logic

This is why IDOR testing requires a human element — a tester who understands the application’s authorization model and can design test cases that challenge it. Automated tools serve as supplements, not replacements, for manual testing in this context.

Preventing IDOR

Effective IDOR prevention requires changes at multiple layers of the application stack — from how objects are referenced to how authorization is enforced.

Indirect Object References

Instead of exposing database IDs directly, use indirect references that map to the actual identifiers on the server side. For each user session, the application maintains a mapping between opaque tokens and real object IDs:

# Instead of: GET /api/orders/5291
# Use: GET /api/orders/a8f3e2b1

# Server-side mapping (per session)
session_map = {
    "a8f3e2b1": {"object_id": 5291, "user_id": 1847},
    "c4d9f0a7": {"object_id": 5292, "user_id": 1847},
}

Because the indirect reference is generated per-session and contains no information about the actual object, an attacker cannot guess or enumerate valid references for other users. This approach eliminates the predictability component of IDOR entirely.

UUIDs as Object Identifiers

Replacing sequential integers with UUIDs (Universally Unique Identifiers) significantly raises the difficulty of enumeration. A UUID v4 like f47ac10b-58cc-4372-a567-0e02b2c3d479 has 122 bits of randomness, making brute-force enumeration infeasible. However, UUIDs are not a complete solution on their own — they reduce the attack surface but do not constitute authorization. If a UUID leaks through logs, referrer headers, or shared links, the object is still accessible without authorization checks.

Use UUIDs as a defense-in-depth measure alongside proper authorization, not as a replacement for it.

Server-Side Authorization Checks

The most critical prevention measure is enforcing authorization on every request that accesses an object. The server must verify that the authenticated user has permission to access the specific resource identified in the request:

def get_order(order_id: str, current_user: User):
    order = db.query(Order).filter(Order.id == order_id).first()
    
    if order is None:
        raise HTTPException(status_code=404)
    
    # Critical: verify ownership before returning data
    if order.user_id != current_user.id and not current_user.is_admin:
        raise HTTPException(status_code=403)
    
    return order

This check must happen at the data access layer, not at the controller or route level. Middleware and decorators can enforce role-based access, but object-level authorization requires knowledge of the specific object being accessed, which is only available after the database query.

Scope Queries to the Authenticated User

A robust pattern is to always scope database queries to the authenticated user, eliminating the possibility of returning another user’s data:

# Vulnerable: fetches any order by ID
order = db.query(Order).filter(Order.id == order_id).first()

# Secure: fetches only the current user's order
order = db.query(Order).filter(
    Order.id == order_id,
    Order.user_id == current_user.id
).first()

With this pattern, even if an attacker guesses a valid order ID, the query returns no result because the additional user_id filter restricts the result set to the authenticated user’s data. This approach is sometimes called “tenant-scoped queries” in multi-tenant applications.

Centralized Authorization Layer

Rather than implementing authorization checks in every endpoint individually, establish a centralized authorization layer that enforces access control policies consistently:

class AuthorizationService:
    def can_access(self, user: User, resource: str, resource_id: str) -> bool:
        policy = self.get_policy(resource)
        resource_obj = self.load_resource(resource, resource_id)
        return policy.evaluate(user, resource_obj)

Frameworks like OPAL (Open Policy Agent for LDAP), Casbin, and Oso provide battle-tested implementations of centralized authorization that integrate with most web frameworks.

IDOR in APIs

Modern applications increasingly rely on APIs for data access, and IDOR vulnerabilities in APIs can be even more impactful than in traditional web applications because APIs often return raw data in structured formats that are easy to parse and exfiltrate at scale.

REST API Vulnerabilities

REST APIs are naturally susceptible to IDOR because their URL structure explicitly encodes object references:

GET    /api/v1/users/{user_id}/documents
PUT    /api/v1/invoices/{invoice_id}
DELETE /api/v1/projects/{project_id}/members/{member_id}

Each path parameter is a potential IDOR vector. Nested resources (like /users/{id}/documents) add complexity because the authorization check must verify both that the user owns the parent resource and has access to the child resource.

Common REST API IDOR patterns include:

  • GET endpoints returning other users’ data — the most frequent and easiest to exploit
  • PUT/PATCH endpoints modifying other users’ resources — enabling data tampering
  • DELETE endpoints removing other users’ objects — enabling data destruction
  • POST endpoints creating resources under other users’ accounts — enabling impersonation

GraphQL API Vulnerabilities

GraphQL APIs present unique IDOR challenges:

Introspection exposure: GraphQL’s introspection feature reveals the entire API schema, including all queries, mutations, and object types. An attacker can discover every possible data access path without guessing:

{
  __schema {
    queryType {
      fields {
        name
        args { name type { name } }
      }
    }
  }
}

Nested query bypass: Authorization might be enforced on top-level queries but not on nested resolvers. Consider this query:

query {
  publicProject(id: "proj-123") {
    name
    members {
      user {
        email
        privateDocuments {
          title
          content
        }
      }
    }
  }
}

If the publicProject resolver checks access but the privateDocuments resolver does not independently verify authorization, the attacker can traverse from a public resource to private data through the graph relationship.

Batching attacks: GraphQL allows multiple queries in a single request, enabling an attacker to enumerate thousands of objects in one HTTP call — making rate limiting less effective.

API Security Best Practices

To protect APIs against IDOR:

  • Validate authorization at every resolver/handler — never trust that a parent endpoint has already verified access
  • Use pagination tokens instead of offset-based pagination — opaque cursor tokens prevent enumeration
  • Implement rate limiting per user, not just per IP — prevents mass enumeration from a single authenticated session
  • Disable GraphQL introspection in production — removes the schema discovery vector
  • Log and alert on access pattern anomalies — a user requesting 10,000 different object IDs in an hour is likely enumerating
  • Return consistent error responses — always return 404 (not 403) for objects the user cannot access, preventing the attacker from distinguishing “exists but unauthorized” from “does not exist”

Developer Best Practices

Eliminating IDOR requires embedding security into the development lifecycle, not bolting it on after deployment.

Design Phase

  • Define an authorization model early: Before writing any code, document which users can access which resources and under what conditions. Use frameworks like RBAC (Role-Based Access Control) or ABAC (Attribute-Based Access Control) to formalize these rules.
  • Avoid exposing internal identifiers: Use indirect references or UUIDs from the start. Refactoring an application from sequential IDs to UUIDs after launch is significantly more expensive.
  • Prefer resource-scoped endpoints: Design API endpoints to operate within the authenticated user’s scope by default (e.g., GET /api/my/orders instead of GET /api/orders/{id}).

Implementation Phase

  • Never trust client-supplied identifiers: Treat every object reference from the client as untrusted input. Validate it against the authenticated user’s permissions before processing.
  • Implement authorization as middleware: Create reusable authorization middleware that can be applied consistently across endpoints, reducing the risk of a developer forgetting to add a check.
  • Use ORM query scoping: Configure your ORM to automatically add tenant/user filters to queries, making it structurally difficult to write a query that returns unauthorized data.
  • Handle errors securely: Return 404 for any resource the user cannot access, whether it exists or not. This prevents information leakage about the existence of objects.

Testing Phase

  • Include IDOR tests in your test suite: Write automated tests that specifically verify authorization boundaries. For every endpoint that accepts an object ID, test that User B cannot access User A’s objects.
  • Conduct regular penetration testing: Manual penetration testing by experienced security professionals remains the most effective way to discover IDOR vulnerabilities that automated tools miss.
  • Use SAST tools for authorization coverage: Static analysis tools can identify code paths that access objects without authorization checks, flagging potential IDOR vulnerabilities before deployment.

Code Review Checklist

During code review, verify each endpoint against these IDOR-specific criteria:

  • Does the handler verify that the authenticated user is authorized to access the referenced object?
  • Is the authorization check at the data access layer, not just the route definition?
  • Does the database query include a user/tenant scope filter?
  • Does the endpoint return 404 (not 403) for unauthorized access?
  • Are indirect references or UUIDs used instead of sequential IDs?
  • Is the authorization logic centralized and reusable, or inline and ad-hoc?

Frequently Asked Questions (FAQ)

What is the difference between IDOR and broken access control?

IDOR is a specific type of broken access control. Broken access control (OWASP A01:2021) is a broad category covering any failure to enforce authorization — IDOR specifically refers to cases where an attacker manipulates a direct reference to an internal object (like a database ID or filename) to access resources belonging to other users.

Can UUIDs alone prevent IDOR vulnerabilities?

No. UUIDs make object identifiers harder to guess, which raises the bar for attackers, but they do not constitute an authorization check. If an attacker obtains a valid UUID through a leaked URL, API response, or log file, they can still access the resource. UUIDs should be used as a defense-in-depth measure alongside proper server-side authorization.

How do I test for IDOR in my application?

Create two user accounts with different roles or data. Log in as User A, capture a request that references an object (e.g., GET /api/orders/42), then replay that request using User B’s session. If User B can access User A’s object, an IDOR vulnerability exists. Tools like Burp Suite’s Autorize extension automate this process across entire applications.

Are GraphQL APIs vulnerable to IDOR?

Yes, GraphQL APIs are often more susceptible to IDOR than REST APIs. GraphQL’s introspection feature can reveal available queries and object types, making it easier for attackers to discover exploitable endpoints. Nested queries can also bypass authorization checks that only protect top-level resolvers. Every resolver that accesses data must independently verify authorization.

What is the business impact of an IDOR vulnerability?

IDOR can lead to mass data breaches, unauthorized financial transactions, account takeover, and regulatory penalties under GDPR, HIPAA, or PCI DSS. Because IDOR exploitation is trivial — often requiring nothing more than changing a number in a URL — these vulnerabilities are frequently exploited at scale by automated scripts, making the impact significantly worse than a single unauthorized access.

Summary

IDOR remains one of the most prevalent and damaging vulnerabilities in web applications precisely because of its simplicity. It does not require buffer overflows, cryptographic weaknesses, or zero-day exploits — it requires only a missing authorization check on an endpoint that exposes an object identifier. The gap between authentication (“who are you?”) and authorization (“are you allowed to access this specific resource?”) is where IDOR lives.

Preventing IDOR requires a multi-layered approach: replacing predictable identifiers with UUIDs or indirect references to reduce the attack surface, implementing server-side authorization checks on every request that accesses an object, scoping database queries to the authenticated user’s context, and testing authorization boundaries as rigorously as you test functionality. In API-driven architectures — whether REST or GraphQL — these principles become even more critical because APIs expose structured data that is trivially parsed and exfiltrated at scale.

The most effective organizations treat authorization not as a feature to be added at the end of development, but as a structural property of their application architecture. When every database query is tenant-scoped, every resolver checks ownership, and every code review includes authorization verification, IDOR vulnerabilities become structurally impossible rather than merely unlikely.

Our services


Share:

Talk to an expert

Have questions about this topic? Get in touch with our specialist.

Sales Representative
Grzegorz Gnych

Grzegorz Gnych

Sales Representative

Response within 24 hours
Free consultation
Individual approach

Providing your phone number will speed up contact.

Want to Reduce IT Risk and Costs?

Book a free consultation - we respond within 24h

Response in 24h Free quote No obligations

Or download free guide:

Download NIS2 Checklist