November 4, 2026
Updated: November 4, 2026
Definition, IDOR vs BOLA, the OWASP and CWE mapping, real CVE cases, multi-account testing and prevention.
Mohammed Khalil

An insecure direct object reference (IDOR) is an access control vulnerability in which an application uses an identifier supplied by the user, such as an account number, file name or record ID, to fetch or change an object without checking that the requester is allowed to access that specific object.
In APIs the same flaw is called broken object level authorization (BOLA), ranked API1:2023 by OWASP, and it falls under A01 Broken Access Control in the OWASP Top 10. The fix is a server-side ownership check on every request, not hidden or random IDs.
Every web application and API refers to things: invoices, messages, files, orders, user profiles, tenants. To fetch one, the client sends a reference, usually an ID in the URL, the request body, a header or a cookie. An IDOR exists when the server trusts that reference and returns or changes the object without asking one question: does this user have the right to this particular object?
The OWASP IDOR Prevention Cheat Sheet describes three ingredients:
Remove the third ingredient and the first two are harmless. That is the most important point in this guide: IDOR is not caused by exposing IDs. It is caused by not checking them.
MITRE classifies the weakness as CWE-639: Authorization Bypass Through User-Controlled Key, lists both IDOR and BOLA as alternate terms, and places it under CWE-863 (Incorrect Authorization). The ACSC, CISA and NSA joint advisory AA23-208A, published July 27, 2023, warned that IDOR flaws are "frequently exploited by malicious actors in data breach incidents" because they are common, hard to prevent outside the development process and can be abused at scale.
Most IDORs sit behind a login. The application correctly confirms who the user is (authentication) but never confirms what that user may touch (authorization). A valid session cookie proves the request came from Alice. It says nothing about whether invoice 1002 belongs to Alice. Frameworks handle authentication well out of the box; object-level authorization depends on business rules that only your code knows, which is why it is so often missing.
The joint advisory groups IDOR into four types. They overlap, and one endpoint can show more than one.
| Type | What the attacker gains | Example (illustrative) |
|---|---|---|
| Horizontal | Access to data of another user at the same privilege level | A customer reads another customer's order history |
| Vertical | Access to data that requires a higher privilege level | A standard user reads an admin-only audit record by its ID |
| Object-level | Ability to modify or delete an object they should not change | A user deletes another user's uploaded file |
| Function-level | Access to a function or action they should not use | A user triggers an approval action reserved for managers |
Horizontal IDOR is the classic case. Vertical and function-level IDOR shade into privilege escalation and broken function level authorization, covered below.
The examples below are illustrative pseudo-requests against example.com, a domain reserved for documentation. They show the logic, not an attack on any real system.
1. An ID in the URL path. Alice is logged in and opens her invoice:
GET /api/invoices/1001 HTTP/1.1
Host: example.com
Cookie: session=<alice-session>The server responds with invoice 1001. Alice changes one digit:
GET /api/invoices/1002 HTTP/1.1
Host: example.com
Cookie: session=<alice-session>If the server returns Bob's invoice with a 200 status, the endpoint has an IDOR. The server checked that the session was valid and that invoice 1002 existed. It never checked that invoice 1002 belonged to Alice.
2. An ID in the request body. A profile update form sends the user ID in a JSON body:
PATCH /api/profile HTTP/1.1
Host: example.com
Cookie: session=<alice-session>
Content-Type: application/json
{"user_id": 4471, "email": "alice@example.com"}If the server updates whatever user_id the client sends instead of the user tied to the session, Alice could change another user's email address, which may lead to account takeover through password reset. The safer design does not accept user_id from the client at all for this action; it takes identity from the session.
3. A reference that is not a number. IDOR is not limited to sequential integers. File names, order codes, email addresses, Base64-encoded values and UUIDs are all object references:
GET /exports/2026-q3-report-acme.pdf HTTP/1.1
Host: example.comIf another tenant's report is reachable by changing the file name, it is the same flaw.
The vulnerable server logic in all three cases looks like this, in pseudo-code:
// Vulnerable: looks up by ID only
invoice = db.invoices.find(id = request.path.id)
return invoice
// Fixed: scopes the lookup to the authenticated user
invoice = db.invoices.find(id = request.path.id, owner_id = session.user_id)
if invoice is null: return 404
return invoice| Location | Typical example | Often missed because |
|---|---|---|
| URL path | /api/users/123/settings | Developers assume the UI only links to the user's own records |
| Query string | ?account=88231 | Parameters added late for convenience |
| Request body (JSON or form) | "order_id": 5520 or a hidden form field | Hidden fields feel trusted |
| Headers and cookies | X-Account-Id or an account cookie | Treated as infrastructure, not input |
| GraphQL arguments | node(id: "…") or a mutation argument | One resolver checks ownership and another does not |
| Nested resources | /orders/77/items/3 | Parent checked, child not |
| File and export names | /downloads/invoice-2026-0042.pdf | Static file serving bypasses app logic |
| Asynchronous jobs | /reports/status?job=af31… | Job IDs assumed to be secret |
| Shared or batch endpoints | /api/bulk?ids=1,2,3 | Each ID in the batch is not checked |

IDOR and BOLA describe the same root cause from two communities. Web application security has used "IDOR" since the 2007 OWASP Top 10, which, as PortSwigger's Web Security Academy notes, popularized the term. API security uses "BOLA," the name the OWASP API Security Top 10 gave the risk in 2019 and kept at number one in 2023.
The OWASP API1:2023 Broken Object Level Authorization entry rates exploitability as easy, prevalence as widespread and detectability as easy, and describes impact ranging from data disclosure to data manipulation and, in some cases, full account takeover. Its scenarios include an API that accepts a vehicle identification number without checking ownership, letting an attacker control other people's cars, and a GraphQL mutation that deletes any document by ID.
Practitioners use the terms interchangeably, but there are nuances. MITRE notes that IDOR is in some ways broader, because it has also been used for path traversal, and the CWE team suspects IDOR is part of BOLA. In practice: if a user can act on an object they do not own by changing its identifier, call it IDOR in a web report and BOLA in an API report, and tag it CWE-639.
| Term | Source | What fails | Example (illustrative) |
|---|---|---|---|
| IDOR | OWASP Top 10 (2007–2013 A4), common web term | Object access by a user-controlled reference without an ownership check | GET /invoices/1002 returns another user's invoice |
| BOLA | OWASP API Security Top 10, API1:2019 and API1:2023 | Same as IDOR, in an API endpoint | An API returns any shop's revenue data when the shop name changes |
| BOPLA | OWASP API3:2023 | Authorization on individual properties of an object (mass assignment or excessive data exposure) | A user sets "role": "admin" in their own profile update |
| BFLA | OWASP API5:2023 | Access to a whole function or endpoint the user should not reach | A standard user calls DELETE /admin/users/9 |
| Broken Access Control | OWASP Top 10, A5:2017, A01:2021, A01:2025 | The umbrella category for all of the above | Any of the rows above |
The line between BOLA and BFLA matters in reports. OWASP's BOLA entry explains that if the user may call the endpoint but changes the object ID, it is BOLA; if the user should not reach the endpoint at all, it is broken function level authorization. Broken object property level authorization is about fields inside an object you are allowed to reach.
IDOR has its own history in the web Top 10:
So when someone asks whether IDOR is still in the OWASP Top 10, the answer is yes: it is one of the named patterns inside the number one category, and the number one API risk on its own.
For how IDOR compares with the other high-impact web flaws we see, read our list of the most common web vulnerabilities.

Privilege escalation is the outcome; IDOR is one way to get there. A horizontal IDOR gives a user the reach of a peer (horizontal privilege escalation). A vertical or function-level IDOR gives a user the reach of a more privileged role (vertical privilege escalation). Privilege escalation can also come from other flaws, such as a misconfigured role, a forged token or a missing function-level check, so not every privilege escalation is an IDOR. For both directions of escalation beyond web apps, including Windows, Linux and cloud IAM causes, see our guide to privilege escalation.
The cases below are public, dated and traced to primary sources: a CVE record, a vendor advisory, a CERT/CC note, the CISA Known Exploited Vulnerabilities (KEV) catalog or a regulator's order. Each one teaches a different lesson.
| Date | Case | What happened | Identifier type | Lesson |
|---|---|---|---|---|
| 2012 | Mobile carrier subscriber data | The joint advisory cites a 2012 incident in which an actor obtained personal data of more than 100,000 mobile device owners from a US communications company's public website | Device identifier | IDOR has been exploited at scale for more than a decade |
| May 2019 | First American Financial (SEC order June 15, 2021) | A document-sharing application exposed over 800 million document images dating back to 2003; the SEC found security staff had identified the vulnerability months earlier but had not remediated it | Sequential document number in a link | Predictable IDs plus no access check equals mass exposure; unremediated findings become regulatory problems |
| Oct 2021 to Feb 2022 | Stalkerware back end, CVE-2022-0732 | Shared infrastructure behind multiple phone-monitoring apps did not authenticate or authorize API requests, exposing data from hundreds of thousands of devices | API object identifier | Shared back ends multiply the blast radius of one missing check |
| Jan 2023 (CVE published) | Instructure Canvas LMS, CVE-2021-36539 | The file preview URL did not deny access to locked or unpublished files for unprivileged users | File identifier in a preview URL | Secondary views (previews, exports) need the same check as the main view |
| Added to KEV Jan 26, 2023 | Telerik UI for ASP.NET AJAX, CVE-2017-11357 | CISA and the vendor describe an insecure direct object reference in RadAsyncUpload that can result in file uploads and, in some cases, remote code execution; KEV marks known ransomware campaign use | Upload handling reference | IDOR is not only a data-read bug; impact depends on what the object controls |
| Jun 2026 (advisory), KEV Jul 7, 2026 | Langflow, CVE-2026-55255 | An authenticated user could execute any flow belonging to another user by specifying the victim's flow ID; the lookup by UUID skipped the ownership check; fixed in Langflow 1.9.1 | UUID | Random identifiers did not prevent exploitation; only the ownership check fixed it |
Sources for the table: the ACSC, CISA and NSA advisory AA23-208A (2012 and 2019 cases); the SEC press release of June 15, 2021 and the original KrebsOnSecurity report of May 24, 2019; CERT/CC VU#229438 and NVD CVE-2022-0732; NVD CVE-2021-36539; NVD CVE-2017-11357; the Langflow security advisory GHSA-qrpv-q767-xqq2 and NVD CVE-2026-55255; and the CISA KEV catalog.
First American shows the cost of predictable identifiers. According to the KrebsOnSecurity report the SEC order followed, anyone with a valid document link could view other people's records by changing a single digit, and document numbers appeared to be issued sequentially. The SEC order focused on disclosure controls: senior executives were not told that information security staff had found the vulnerability several months earlier. First American agreed to pay a $487,616 penalty without admitting or denying the findings. An IDOR finding that sits unfixed is a governance issue, not only a technical one.
The stalkerware case shows how far one flaw can reach. CERT/CC reported that an unauthenticated remote attacker could access personal information collected from any device running one of the affected app variants, and that it knew of no practical solution because the infrastructure provider had to fix it.
Langflow shows why UUIDs are not a fix. Langflow's flow IDs are UUIDs, which are hard to guess. The flaw still existed because the helper that loaded a flow by UUID did not filter by the requesting user, while the alternate lookup path did. Once attackers can learn an ID, from logs, shared links, other API responses or a colleague, random IDs offer no protection. CISA added the CVE to the KEV catalog on July 7, 2026, which means it had evidence of exploitation in the wild.
Telerik shows IDOR impact is not limited to reading data. When the object reference controls where a file goes or what a component does, the impact can reach code execution. Severity depends on the object, not on the bug class name.
IDOR testing is authorization testing, and authorization only makes sense relative to who owns what. That is why the core technique uses at least two accounts. The OWASP Web Security Testing Guide covers it as WSTG-ATHZ-04, Testing for Insecure Direct Object References, and the joint advisory recommends mapping every location where user input references objects and testing with users of different privilege levels.
Run these steps only in an environment you own or are authorized to test, with test accounts and test data.

Testers also look for the places where the matrix is most likely to break: features added recently, endpoints used only by mobile apps, admin and support tooling, file and report exports, invitations and sharing links, and any flow where one object references another (an order that references an address, a ticket that references an attachment). For GraphQL-specific patterns such as per-resolver authorization, see our guide to GraphQL API vulnerabilities.
A good finding write-up states the account used, the object owner, the exact request and response, the expected matrix cell and the business impact. Our penetration testing report guide shows how that evidence should be structured so developers can reproduce and fix it.
Once a tester has built a role matrix, keep it. The OWASP Authorization Testing Automation Cheat Sheet describes how to formalize the expected authorization matrix and run integration tests against it. In practice, that means a CI test for each sensitive endpoint that logs in as user B and asserts that user A's object returns 403 or 404. OWASP's BOLA guidance says the same: write tests for the authorization mechanism and do not deploy changes that make them fail.
Automated scanners are useful for many vulnerability classes, but IDOR is hard for them for a structural reason: the request that exploits an IDOR is a perfectly valid request. Nothing in the syntax is malicious. Only knowledge of ownership tells you the 200 response is wrong.
OWASP put it plainly in its 2017 Broken Access Control entry: SAST and DAST tools "can detect the absence of access control but cannot verify if it is functional." The joint advisory adds that not all DAST tools can detect IDOR, and those that can may need specific environment setup and custom rules.
| Scanner limitation | Why it matters for IDOR | What a human tester adds |
|---|---|---|
| Usually runs with one session | IDOR needs a second identity to prove cross-user access | Two or more accounts per role and tenant |
| Does not know who owns which object | A 200 response looks like success, not a breach | Ground truth from objects the tester created |
| Treats IDs as opaque strings | Cannot judge whether a returned record is someone else's data | Reads the response and recognizes another user's data |
| Weak on multi-step and nested flows | Many IDORs sit in exports, shares, approvals and child objects | Follows business workflows end to end |
| Limited GraphQL and asynchronous coverage | Resolver-level and job-ID checks are missed | Tests each resolver and job reference |
| SAST sees code, not policy | Cannot know the business rule "managers see their team's records only" | Compares behavior against the intended policy |
Tools still help. Proxy extensions that replay requests with a second session, API scanners configured with multiple users, and schema-driven test generators can cover the repetitive part of the matrix. Our roundup of API security testing tools compares options. The judgment about whether a response violates policy, and the creativity to find the reference nobody listed, still come from people. That is also why bug bounty programs report so many access control findings; our comparison of penetration testing vs bug bounty explains when each fits.
Prevention comes down to one rule from OWASP A01:2025: access control is only effective in trusted server-side code, where the attacker cannot modify the check. Everything else is defense in depth.
| Control | Strength | What it does | Notes |
|---|---|---|---|
| Server-side object-level authorization on every request | Required | Checks that the requester may perform this action on this object | Covers read, update, delete, export and every HTTP method |
| Scope data access to the user or tenant | Required | Queries only records the user can reach, so other records are never loaded | For example, look up the invoice through the current user's invoices |
| Deny by default | Required | Any object or function without an explicit rule is refused | OWASP A01 lists it first |
| Centralized authorization policy | Strongly recommended | One middleware, policy engine or data-layer filter enforces rules everywhere | Prevents the "one endpoint forgot" problem |
| Identity from the session, not the client | Strongly recommended | The server ignores user_id or tenant_id values sent by the client for the caller's own actions | Removes a whole class of body-parameter IDOR |
| Indirect references | Defense in depth | Maps a per-user or per-session reference (1, 2, 3 in "your list") to the real ID on the server | Exposes no global IDs; still check authorization |
| Random, non-sequential IDs (UUIDs) | Defense in depth | Makes enumeration much harder | Never a substitute for authorization, as Langflow showed |
| Authorization tests in CI | Strongly recommended | Two-user tests fail the build when a check disappears | Turn every IDOR finding into a regression test |
| Logging, alerting and rate limits | Detective | Spots enumeration patterns, such as bursts of 403 and 404 responses | Reduces scale; does not fix the flaw |
Put the check where the object is loaded, not only at the route. The OWASP cheat sheet's example contrasts looking up a project from all projects with looking it up from the current user's projects. The same idea in language-neutral pseudo-code:
// Avoid: global lookup, then hope a later check runs
project = Projects.find(request.id)
// Prefer: lookup scoped to what the caller may access
project = Projects.where(tenant_id = session.tenant_id)
.where(member = session.user_id)
.find(request.id)
if project is null: return 404 // do not reveal whether it exists
// For actions beyond read, check the action too
if not policy.allows(session.user, "delete", project): return 403Three implementation details matter:
The OWASP Authorization Cheat Sheet covers broader design choices, such as enforcing least privilege, validating permissions on every request and preferring attribute- or relationship-based models where roles alone are too coarse.
An indirect reference map replaces the real database key with a value that only means something for the current user or session. A user who sees "document 3" in their list sends 3; the server translates it to the real ID from that user's own list, so a reference cannot point outside it. The joint advisory recommends indirect reference maps and replacing exposed IDs with cryptographically strong random values such as UUIDs, while noting that UUIDs should not be used as a security capability.
Use indirect references and random IDs to make enumeration harder, and keep the object-level check anyway. The Langflow case is the reminder: the IDs were UUIDs and the flaw was still exploitable.
IDOR is a design and code-review problem first. Add an authorization model to the threat model for every feature that introduces a new object type, review access checks during code review, and keep the role matrix as a living test artifact. Our secure SDLC guide shows where these checks belong in each phase. For context on how often API authorization issues appear in industry data, see our API security statistics.
Use this checklist when you scope or review an authorization test:
IDOR (insecure direct object reference) is a flaw where an application lets you reach someone else's data or actions just by changing an ID in a request, because the server does not check whether that object belongs to you. It is a type of broken access control.
They describe the same root cause: a missing object-level authorization check on a user-controlled identifier. IDOR is the traditional web application term from the OWASP Top 10; BOLA is the API term, ranked API1 in the OWASP API Security Top 10 in 2019 and 2023. MITRE lists both as alternate terms for CWE-639.
Privilege escalation is the result: gaining access beyond what your account should have. IDOR is one cause. A horizontal IDOR gives you another user's data at the same level; a vertical or function-level IDOR gives you access reserved for a higher role. Privilege escalation can also come from other flaws, such as role misconfiguration or token forgery.
Yes. IDOR was its own category (A4) in 2007, 2010 and 2013, was merged into A5:2017 Broken Access Control, and is named as a common case inside A01:2025 Broken Access Control, the top-ranked category. In the OWASP API Security Top 10, the same flaw (BOLA) is API1:2023.
No. Random identifiers make IDs harder to guess, which reduces enumeration, but IDs leak through shared links, logs, emails and other API responses. Langflow's CVE-2026-55255 involved UUID-based flow IDs and was still exploitable. Only a server-side ownership check prevents IDOR.
Sometimes, with effort. Scanners usually run with one session and cannot tell whether a successful response contains another user's data. Some DAST and API tools can test with multiple users if configured with custom rules, but OWASP and the joint ACSC, CISA and NSA advisory both say manual, multi-account testing is still needed.
CWE-639, Authorization Bypass Through User-Controlled Key. It is a child of CWE-863 (Incorrect Authorization) and the parent of CWE-566 (Authorization Bypass Through User-Controlled SQL Primary Key). CVE records for IDOR often also cite CWE-284 or CWE-285.
It depends on the object. Reading a public display name is low impact; reading financial records, changing another user's email, deleting files or triggering actions can be high or critical. OWASP rates BOLA exploitability as easy, and the cases above range from mass data exposure to remote code execution.
Add a server-side authorization check where the object is loaded, scope queries to the current user or tenant, deny by default, take the caller's identity from the session instead of the request, and add a two-user regression test. Random IDs and indirect references are useful extra layers, not the fix.
IDOR is simple to explain and easy to miss, because every exploiting request looks legitimate. The defense is equally simple to state: check ownership on the server for every object, every action and every path, and prove it with tests that use more than one account.
DeepStrike's web application penetration testing is built for this class of flaw: rigorous manual testing based on how your application is supposed to behave, security checks from multiple users' perspectives, findings validated through exploitation, fix recommendations, a technical presentation for your engineers and re-testing to confirm the fixes hold. If your exposure is mostly APIs, our API penetration testing guide explains how BOLA, BFLA and tenant isolation testing are scoped. To discuss your application, contact DeepStrike.
Mohammed Khalil is a Cybersecurity Architect at DeepStrike, specializing in advanced penetration testing and offensive security operations. With certifications including CISSP, OSCP, and OSWE, he has led numerous red team engagements for Fortune 500 companies, focusing on cloud security, application vulnerabilities, and adversary emulation. His work involves dissecting complex attack chains and developing resilient defense strategies for clients in the finance, healthcare, and technology sectors.

Stay secure with DeepStrike penetration testing services. Reach out for a quote or customized technical proposal today
Contact Us