Skip to content

IDOR Vulnerability: Examples, Testing and Prevention

IDOR vulnerability explained: real cases, IDOR vs BOLA, the fixes that work, how abuse shows in your logs, and how we test for it from $4,000.

Mark KissBy , Founder & CEOUpdated 15 min read

Web Application Penetration TestingFrom $5,200Fixed scope, free retest, no hourly billing.

Get my fixed price

An IDOR vulnerability (insecure direct object reference) is an access control flaw where an application returns or changes a record because the request named it, without checking that the person asking is allowed to touch that record. Change an order number, an account ID or a file name in a request, and the server hands back someone else’s data. In APIs the same flaw is called broken object level authorization (BOLA), and it is the first entry on the OWASP API Security Top 10. The fix is a server-side ownership check on every object, on every request; hiding or randomizing the identifier only slows an attacker down.

Every web application penetration test and API penetration test we run checks every role and tenant for it, at published prices: web applications from $5,200 and APIs from $4,000, fixed in writing, with a free retest.

What is an insecure direct object reference?

OWASP’s IDOR Prevention Cheat Sheet breaks the flaw into three parts: an object (a record, a file, an account), a reference to it that the client can see and send (an ID, a UUID, an account number, a token or a slug), and a missing object-level authorization check. Logging in does not protect you: the attacker is usually an authenticated customer, trial user or partner.

The July 2023 joint advisory from CISA, NSA and the Australian Cyber Security Centre, AA23-208A, describes four forms: horizontal (another user’s data at the same privilege level), vertical (data that needs a higher privilege), object-level (modifying or deleting objects) and function-level (using actions you should not). It stresses that IDOR applies to APIs, including those behind mobile apps, and that attackers exploit it at scale with automated tools. MITRE catalogs the weakness as CWE-639, Authorization Bypass Through User-Controlled Key.

IDOR was its own category in the OWASP Top 10 through 2013, was merged into Broken Access Control in 2017, and that category has ranked first since 2021. In the OWASP Top 10:2025, OWASP reports that 100% of the applications tested had some form of broken access control. Our OWASP Top 10 2025 explainer covers the rest of the list.

IDOR vs BOLA (broken object level authorization)

IDOR and BOLA are the same flaw. IDOR is the older web application name; BOLA is the name OWASP gave it in the first API Security Top 10 in 2019 and kept at the top as API1:2023, rated easy to exploit and widespread. Our OWASP API Security Top 10 explainer covers the other nine. A “BOLA attack” is an IDOR exploited through an API. Reports often blur it with its neighbors:

Term What is missing Plain example Reference
IDOR / BOLA A per-object ownership check A customer changes the invoice number and sees another customer’s invoice CWE-639, API1:2023, ASVS 8.2.2
BOPLA (property level) A per-field check A user reads a field they should not see, or sets one such as “role” (mass assignment) API3:2023, ASVS 8.2.3
BFLA (function level) A per-function privilege check A standard user calls an admin endpoint that was hidden but never protected API5:2023, ASVS 8.2.1
Path traversal Validation of a file path A file name parameter reaches files outside the intended folder CWE-22

Unlike XML external entity injection or remote code execution, an IDOR needs no malformed input. Every request is well formed and every response looks normal, which is why scanners and WAFs miss it and why it can stay in production unnoticed.

IDOR vulnerability examples from the public record

First American: found by a pentest, made public by a journalist

First American Financial’s EaglePro application shared title and escrow documents through links. According to the SEC’s June 2021 order, the company’s own manual penetration test, finalized January 11, 2019, found that “replacing the document ID in the web page URL with another sequential number” opened unrelated documents without authentication. A clerical error logged it as low severity instead of medium, which stretched the fix deadline from 45 days to 90: May 8, 2019. The deadline passed. On May 24, 2019, a journalist reported that the flaw exposed over 800 million document images dating back to 2003, including Social Security numbers and financial information.

The SEC’s $487,616 penalty was for disclosure-control failures: the executives speaking publicly had not been told of the earlier finding. New York’s Department of Financial Services followed with a $1 million consent order in November 2023 under 23 NYCRR 500.3 and 500.7, noting that the links required no login and never expired.

The pentest found it; the tracking failed. Rate IDOR findings on the data behind them and how easily the IDs can be walked, then track them to closure and retest, as our vulnerability remediation guide describes.

Cases from CISA and OWASP

The CISA advisory cites a 2021 stalkerware case in which an IDOR in the collection server (CVE-2022-0732) exposed texts, call records, photos and locations from hundreds of thousands of devices. OWASP’s API1:2023 page describes a carmaker’s API that let a user control vehicles they did not own by supplying a VIN, and a GraphQL delete mutation that accepted any document ID; our GraphQL security testing guide covers resolver-level authorization.

Where IDORs hide

Where the reference lives What goes wrong Typical impact
Record ID in the URL or query string The record is loaded by ID alone Other customers’ orders, invoices or tickets
User or account ID in a form or JSON body The submitted ID is trusted on update Changes to another user’s profile or settings
Tenant ID in a header or body The tenant comes from the request, not the session Cross-tenant access in a SaaS platform
Child object under a parent Only the parent is checked Another account’s statements through your own path
File name or document number Downloads bypass the authorization layer Other users’ documents
Export or background job ID The result is fetched with no owner check Bulk data in one request
Shareable links The link is the only control and never expires Anyone holding the link gets in, as at First American
The API behind a mobile app The app hides the ID, so nobody checked the API Account data for every user
AI assistant or agent tools The tool uses a service account, not the user’s rights The assistant retrieves records the user could not

Why scanners miss IDOR, and why UUIDs don’t fix it

A scanner sees a normal status code and well-formed data; it cannot know the invoice belongs to someone else, because ownership is business context. The CISA advisory recommends dynamic testing but cautions that not every tool detects IDOR. The reliable method is a person testing with at least two user accounts, plus accounts at different privilege levels where relevant, which is how the OWASP Web Security Testing Guide test WSTG-ATHZ-04 frames it. More in DAST vs penetration testing.

Random identifiers help only as a second layer. RFC 9562, the 2024 UUID standard, says not to assume UUIDs are hard to guess and forbids using them as security capabilities (identifiers whose mere possession grants access). UUIDv7 begins with a 48-bit timestamp. And IDs leak through other API responses, shared links, emails, logs and referrer headers.

How to prevent IDOR vulnerabilities

  1. Take identity from the session, never from the request. User and tenant IDs come from the authenticated session or a verified token, not from a URL, body field, header or cookie.
  2. Scope every lookup to the caller. Load the record through the caller’s relationship (“this user’s projects, with this ID”), or put owner and tenant in the query, instead of loading by ID and checking afterward.
  3. Enforce authorization in one place and deny by default. OWASP’s A01:2025 guidance asks you to implement access control once, reuse it everywhere, and base it on record ownership.
  4. Check writes, deletes, exports and batch calls, not just reads, and every GraphQL resolver, API version, file download and background job.
  5. Add a data-layer backstop for multi-tenant products. Row-level security, such as PostgreSQL’s, can stop a missed check from returning another tenant’s rows. Superusers and roles with BYPASSRLS always bypass it, and table owners do unless the table uses FORCE ROW LEVEL SECURITY, so connect the application as a non-owner role without BYPASSRLS.
  6. Give files and shared links an owner check or a short expiry. Never permanent public links.
  7. Return the same response for “not found” and “not allowed” where a record’s existence is itself sensitive.
  8. Treat indirect reference maps and random, non-sequential IDs as defense in depth, not as the control. The CISA advisory recommends both.
  9. Run two-user authorization tests in CI. OWASP’s API1:2023 guidance says to write authorization tests and not deploy changes that break them; a test where user B requests user A’s object and expects a refusal catches regressions.
  10. Make AI agents act with the user’s rights. ASVS 5.0 requirement 8.3.3 asks that access decisions use the originating user’s permissions, not an intermediary’s. An assistant using a broad service account becomes a confused deputy that fetches any customer’s record on request; our agentic AI security and MCP server security guides cover this.

The OWASP ASVS 5.0 authorization chapter makes this verifiable: requirement 8.2.2 (Level 1) names IDOR and BOLA, and 8.4.1 (Level 2) requires cross-tenant controls; see our ASVS explainer and API security best practices.

IDOR example: the request and the scoped query that fixes it

Step 2 is the one that removes most IDORs, so here it is in full. A customer on account 77 opens their own invoice, then asks for the next number:

GET /api/invoices/1042    200 OK, account 77's invoice
GET /api/invoices/1043    200 OK, account 91's invoice

Both requests carry the same valid session. The second one works because the server looks the record up by the identifier alone:

-- Vulnerable: any logged-in user can read any invoice
SELECT * FROM invoices WHERE id = :invoice_id;

-- Fixed: the owner comes from the session, never from the request
SELECT * FROM invoices
WHERE id = :invoice_id AND account_id = :session_account_id;

With the fixed query, the request for invoice 1043 finds no row and returns the same 404 as an invoice that does not exist. The OWASP cheat sheet linked above shows the same change in framework code: load the record through the current user’s relationship to it instead of searching every record. Write the scoped lookup into your secure coding practices as the default, so that a query by ID alone stands out in code review.

How to detect IDOR abuse in your logs

Successful IDOR abuse looks like ordinary traffic: authenticated requests, valid parameters, 200 responses. A WAF cannot tell whose invoice is being read. Detection depends on the application recording who asked for which object, and whose it was. OWASP’s A01:2025 guidance says to log access control failures and alert on repeats; the CISA advisory notes that 403 and 404 responses are associated with enumeration and recommends baselining behavior and centralizing application logs in a SIEM.

Log source Signal What it means
Application authorization log Repeated access-denied events for one user across many object IDs Someone is probing, and the check is holding. Only exists if denials are logged with user and object ID
Web server, load balancer or API gateway logs Bursts of 403 and 404 responses from one session or token Enumeration in progress. A successful IDOR returns 200, so this catches the probing, not the theft
The same access logs One session requesting many distinct IDs on an object endpoint, often in sequence Scraping through an IDOR. Baseline admin tools and exports first
Application data-access audit log The actor’s user or tenant differs from the object’s owner, with no share on record The abuse itself, and the highest-fidelity signal you can build
Database row-level security errors Policy-violation errors on INSERT or UPDATE, when a write would create or move a row into another tenant A missed application check caught by the backstop. Reads, updates and deletes aimed at another tenant’s existing rows are filtered without notice and log nothing, so pair this with the application data-access audit log

When a test finds an IDOR, search these logs for the same pattern as far back as you retain them. That look-back, with your counsel, decides whether you have a fixed bug or a notifiable event, which matters for any NYDFS Part 500 covered entity. One IDOR rarely travels alone, because it usually means authorization is written endpoint by endpoint: close the reported instance now, then fix the pattern everywhere.

How Invadel tests for IDOR and BOLA

Object-level authorization is the core of every web application and API engagement we run, following WSTG-ATHZ-04 and API1:2023 (our API penetration testing methodology has the full plan).

  • Accounts. At least two accounts per role and per tenant, so there is always a “user B” whose data “user A” must not reach. An OpenAPI spec or Postman collection lets us inventory every endpoint that takes an identifier.
  • Coverage. Each object reference is tried as another user of the same role, a lower role, another tenant and an anonymous caller, for read, update and delete. Exports, background jobs, older API versions and the mobile app’s API are in scope too. Where an endpoint takes a sequential or guessable ID, identifier fuzzing with ffuf walks the range under one account’s session, and a tester then checks each returned record against its owner.
  • Reporting and retest. Each finding states impact in business terms with reproduction steps your developers can replay (see a sample report). The free retest replays the same cross-account requests after your fix and updates the report.

How we typically rate an IDOR, before your data adjusts it (our guide to reading results explains how severity is adjusted in a report):

Situation Typical severity
No login needed, sequential IDs, sensitive personal or financial data Critical
Any self-registered user can read or change other customers’ records High to critical
One tenant can reach another tenant’s data High to critical
Needs a random ID that is not exposed anywhere else Medium, rising if the ID leaks
Read-only access to low-sensitivity fields Low

What it costs to test for IDOR

Engagement Small Medium Large
Web application (one or two roles at small, multi-tenant at large) $5,200 $7,800 $12,500+
API (about a dozen endpoints and one or two roles at small) $4,000 $6,000 $9,500+
Mobile application, including the API behind it $6,000 $8,500 $14,000+
Source code review, missing checks traced to file and line $4,800 $8,900 $12,000

Multi-tenant products usually sit in the medium or large column, because every tenant boundary multiplies the cross-account work; SaaS penetration testing covers tenants, roles and the API as one engagement, and our page on penetration testing for SaaS companies explains how we test the tenant boundary that enterprise buyers ask about. Send your scope details and the price comes back fixed in writing, with no sales call; onboarding follows within 24 hours of a signed proposal. Each penetration test includes the cross-account retest described above (a source code review gets a free re-review once fixes merge), and an attestation letter for the enterprise customers who ask how you keep their data apart from other tenants’. To add several tests together, use the pricing calculator.

Frequently asked questions

What is an IDOR vulnerability in simple terms? An application lets you reach a record by naming it, such as an order number or account ID, and never checks that the record is yours. Change the number and you get someone else’s data.

Is IDOR the same as BOLA? Yes. Broken object level authorization (BOLA) is the name the OWASP API Security Top 10 uses for IDOR in APIs, where it ranks first, and a BOLA attack is an IDOR exploited through an API. Both map to CWE-639.

What is an example of an IDOR vulnerability? First American Financial’s EaglePro document links: changing the sequential document number opened unrelated title and escrow documents without a login, in a repository of about 800 million document images, according to the SEC’s 2021 order. Everyday examples are invoice or ticket numbers in a URL.

What is the difference between IDOR and privilege escalation? IDOR is one route to privilege escalation. Reaching another user’s data at your own level is horizontal escalation; reaching data or functions reserved for a higher role is vertical escalation. Most IDORs are horizontal.

Do UUIDs prevent IDOR? No. They make identifiers harder to guess, but RFC 9562 says UUIDs must not be used as security capabilities, and IDs leak through other responses, links and logs. Use them behind a server-side ownership check, not instead of one.

Can a vulnerability scanner find IDOR? Rarely. The exploiting request returns valid data with a normal status code, and the scanner cannot know who owns the record. It takes a tester with two accounts per role, or a review of the authorization code.

How is an IDOR finding rated with CVSS? By who can exploit it and what they reach. Under the CVSS v3.1 specification, a network-reachable IDOR that any logged-in user can use to read sensitive records (Privileges Required: Low, Confidentiality: High) has a base score of 6.5, Medium. If no login is needed (Privileges Required: None) the same flaw scores 7.5, High, and where records can also be changed (Integrity: High) the scores are 8.1 and 9.1, which is Critical. The base score cannot see how sensitive the data is or how many records can be walked, so the reported severity is then adjusted for those, as in the table above.

The short version

An IDOR vulnerability is a missing ownership check: the server trusts the identifier in the request. In APIs it is called BOLA, and it tops the OWASP API Security Top 10. Fix it with scoped queries, central deny-by-default authorization and two-user tests in CI, treat random IDs as a backstop, and log enough to see who touched whose data. To find the ones you already have, book an API penetration test (from $4,000) or a web application penetration test (from $5,200), or send your scope for a fixed price.

Mark Kiss

Written by

Mark Kiss, Founder & CEO

15+ years in the field. Focus: Offensive security & strategy. Part of the team that scopes, tests, and reports for our clients. Full profile →

All articlesApplication Pentesting

Find out what an attacker sees.

Tell us what to test and see your fixed price.

Prefer the full scoping questionnaire? 
Start the conversation

Get a quick proposal

We are online