Blog · API Security

BOLA vs IDOR: same bug, different name?

IDOR and BOLA name the same broken-authorization failure from two different eras of security. Here is what actually separates the two words, why switching to UUIDs does not fix either one, why scanners walk straight past them, and the two-account request that settles whether you have one.

Planck Proof · Offensive Security Team · September 10, 2026 · 8 min read

In April 2026, ants.gouv.fr, the government portal behind every French passport and national ID card, was reported to have suffered a breach in which someone changed a number in a request and walked out with the personal records of millions of citizens. The cause was reportedly mundane: an insecure direct object reference in the agency's API, an endpoint that returned whatever record the identifier in the request pointed at, without checking whether the caller was allowed to see it.

If you have read the OWASP API Security Top 10, you know that bug by another name: Broken Object Level Authorization, API1:2023, the number-one API risk. So which is it, IDOR or BOLA? The short answer is that they are the same bug, described by two communities at two points in time. The longer answer is worth having, because the naming argument hides the one thing that actually matters: whether an attacker can reach an object that is not theirs, and whether you can prove it.

Where the two names come from

IDOR is the older term. It comes out of web application testing, where OWASP used it for years to describe any case where a user-supplied value (a row id in a URL, a filename, an account number in a hidden field) points straight at an object and the server trusts it without checking ownership. Change ?invoice=1041 to ?invoice=1042, receive someone else's invoice: that is textbook IDOR.

BOLA arrived when OWASP built a Top 10 specifically for APIs, first in 2019 and again in 2023. APIs made the problem far worse: they expose object identifiers directly, in enormous numbers, to clients the server does not control, and they lean on the caller to send the right id. OWASP named the API version Broken Object Level Authorization and placed it at the very top of the list, API1, because it is both the most common and among the most damaging API flaws in the wild. BOLA is IDOR grown up and moved into the API layer, where it does the most harm.

So are they identical?

Close enough that working pentesters use the words interchangeably, with one distinction worth keeping. IDOR names the mechanism: a direct, attacker-controllable reference to an object. BOLA names the failure: the object-level authorization check that should have stopped the request never ran. Most BOLA findings are IDORs, because a guessable or observable identifier is the usual way in. But BOLA is the broader idea: even a hard-to-guess identifier is a BOLA the moment the server hands back the object with no ownership check. The identifier being predictable is what makes it easy to exploit; the missing check is what makes it a vulnerability.

DimensionIDORBOLA
OriginGeneral web application testing termOWASP API Security Top 10 (2019, 2023)
Where it is listedUnder Broken Access Control in the OWASP Top 10API1:2023, ranked first
ScopeAny direct object reference, web or APIObject-level authorization in APIs specifically
Names theMechanism: the attacker-controlled referenceFailure: the missing per-object authorization
Root causeServer trusts a client-supplied referenceNo check that the caller owns the object
How you prove itIdentical: two identities, and one reads the other's object

The proof nobody prints

Read a dozen "BOLA vs IDOR" explainers and you notice what every one of them is missing: the proof. They define the terms, maybe show a one-line snippet of a vulnerable controller, and stop. None of them show the single artifact that decides whether you actually have the bug: two requests from two accounts, and what came back.

Here is what that looks like, as two commands anyone can run. Account A and account B are ordinary users of the same API. Account A authenticates as themselves, then asks for an order that belongs to account B. Illustrative example, not a specific customer result.

# Baseline: account A requests its own order
curl -s https://api.example.com/api/v3/orders/50713 \
  -H "Authorization: Bearer <ACCOUNT_A_TOKEN>"

# -> 200 OK
{ "order_id": 50713, "user_id": 8842, "email": "[email protected]", ... }

# Attack: account B's order, requested with account A's token
curl -s https://api.example.com/api/v3/orders/50714 \
  -H "Authorization: Bearer <ACCOUNT_A_TOKEN>"

# -> 200 OK
{ "order_id": 50714, "user_id": 9317, "email": "[email protected]", ... }

What proves the flaw: the second curl uses account A's token throughout, yet it returns account B's user_id and email with a clean 200 OK and no 403. Account A was never re-authenticated as account B; the server just handed over the object because the identifier in the path matched, not because it checked who was asking. That is BOLA, and the reference in the path is the IDOR. One request pair proves it; no amount of prose does.

The oracle matters as much as the request. A 200 OK on its own proves nothing: the endpoint might return an empty body, a redacted record, or a public object anyone is allowed to read. The finding is real only when the response contains data that provably belongs to the other identity, a field that ties the object to account B and not to account A. That is the exact line between a genuine cross-tenant read and a false positive, and it is precisely the line a signature cannot see.

Why UUIDs don't fix it

The most common "fix" for an IDOR is to stop using sequential integers and switch to UUIDs, on the theory that 50714 is guessable and a3f1c9e2-4b6d-... is not. It does not fix the bug. It hides the easiest way to find it.

Authorization and guessability are different problems. A UUID makes an identifier hard to enumerate blind, but the server still returns the object to anyone who presents it, so any path by which an attacker learns a valid id reopens the door: a shared link, a referrer header, a verbose log, a mobile app cache, a support ticket, or a second endpoint that lists ids and is trusted by a first. The only real fix is the check UUIDs skip: on every object request, confirm that the authenticated caller is allowed to reach that object. Unguessable names are defense in depth, not authorization.

Why scanners and DAST miss it

If BOLA is the top API risk, why does it survive scanners, DAST, and most automated testing? Because those tools match patterns, and BOLA has no pattern to match. A scanner watches a request go out and a 200 OK come back and has no idea whose data is in the response. It has no concept of "account A" and "account B," no notion of which object should belong to whom, so a successful cross-tenant read looks identical to a user reading their own record. See agentic pentesting vs DAST for why that gap is structural rather than a tuning problem.

Finding BOLA takes what a scanner does not have: at least two identities, an understanding of which objects each should and should not reach, and a request that tests the boundary between them. It is authorization logic, not a payload. This is also why pointing a large language model at the problem without a verification step backfires. A Stanford study published in late 2025 found an AI agent could out-test most human pentesters on cost, yet reported findings at roughly a one-in-five false-positive rate (about 18 percent), including "successes" that were nothing of the kind, where the strongest human testers sat near zero. The lesson is not that machines cannot find BOLA. It is that a claimed BOLA is worthless until something has actually replayed the two-account request and checked the response.

The bill for getting it wrong

BOLA is not a lab curiosity; it is how modern data breaches happen. The French ID portal above is one 2026 example. Here is another from the year before. In mid-2025, security researchers Ian Carroll and Sam Curry examined McHire, the McDonald's hiring platform built on Paradox.ai, and found two flaws that rhyme with this whole article: a test administrator account still protected by the password 123456, and, behind it, an insecure direct object reference in an internal API. Decrementing an applicant id in an API request returned other applicants' names, contact details, and chatbot conversation transcripts, with exposure reaching up to 64 million job applications. One incrementing number, tens of millions of records, the same bug OWASP has ranked first for years.

The pattern repeats because the missing check is invisible. Nothing crashes, nothing throws an error, the endpoint returns 200 OK every time. It looks fine in a demo, it looks fine to a scanner, and it looks fine right up until someone iterates the identifier.

How Operator proves it

This is the exact class of bug Operator is built to catch, and the reason it can is the reason the explainers cannot: it does not stop at flagging a suspicious endpoint. Given your API specification and a token for each role, it enumerates the objects each identity can request, replays the boundary between them, and reports a finding only when a response provably contains another identity's data, with the request pair attached as evidence. Every finding ships with the two-account reproduction you saw above, so an engineer confirms it in minutes instead of debating whether it is real. That is the difference between "your API might have a BOLA" and "here is account A reading account B's order, run it yourself."

We wrote more about proof-based delivery in how agentic pentesting proves an exploit, about this bug class in BOLA testing, and about its close cousin at the function layer in BOLA vs BFLA. And we published a real one: a master-PIN IDOR in Rently, CVE-2026-75960.

FAQ

Common questions

Is IDOR the same as BOLA?

They describe the same class of bug from two eras of naming. IDOR (Insecure Direct Object Reference) is the older, general term from web application testing: a user-supplied identifier points straight at an object with no check that the caller owns it. BOLA (Broken Object Level Authorization) is what OWASP named the API version of that failure when it built the API Security Top 10, where it sits at number one. When the object is exposed through an API, the two words point at the same finding.

Do UUIDs fix IDOR or BOLA?

No. Swapping a sequential ID for a UUID only makes the identifier harder to guess; it does not check whether the caller is allowed to reach that object. If the server still returns the record to anyone who presents the identifier, the authorization bug is intact, and UUIDs leak through logs, referrer headers, shared links, and other endpoints. The fix is a server-side check that ties every object to its owner, not an unguessable name.

Can a scanner find BOLA?

Rarely. A scanner matches request and response patterns and has no concept of which user should own which object, so it cannot tell a legitimate 200 OK from one that returned another tenant's data. Finding BOLA takes two identities and a check of whether one can read the other's object, which is why it is best proven with a reproducible request rather than flagged by a signature.

Is IDOR still in the OWASP Top 10?

Yes, under different names in different lists. In the OWASP API Security Top 10, Broken Object Level Authorization is API1:2023, the top risk. In the main OWASP Top 10 for web applications, IDOR sits under Broken Access Control, which has ranked first since 2021. The bug never left; only the label changes with the list.

Get Started

Find out if your API leaks across accounts

Give Operator your spec and a token per role. It tests the boundary between identities and proves any object one user can reach that belongs to another.