BOLA vs IDOR Technical Distinction and Testing Methodology

Understanding the distinction helps testers find and fix authorization failures systematically.

· 9 min read
Cover illustration for “BOLA vs IDOR Technical Distinction and Testing Methodology”
Access Control · November 1, 2026 · 9 min read · 1,991 words

IDOR and BOLA describe the same authorization failure from different angles. IDOR names the object reference a user can tamper with, while BOLA names the server-side check that failed to stop unauthorized access. The distinction tells testers where to look, how to prove the failure across different sessions, and what evidence an engineering team needs to fix it.

Why IDOR and BOLA name the same failure from different angles

A researcher changes /api/orders/10021 to /api/orders/10022 and receives another customer’s complete order record, including their name, address, items, and the last four digits of their payment method. No exploit chain is required to expose it. The request reaches a real order, but the server never establishes whether that order belongs to the caller. The identifier substitution reveals the failure, while the unauthorized response proves it.

Insecure direct object reference, or IDOR, describes that exploitable symptom. A user-controlled reference reaches an object the user should not be able to access. Broken object-level authorization, or BOLA, names the failure to check that access. These are not competing explanations of the incident. One names the handle the attacker manipulates, while the other names the check the application omitted.

The web-application security community coined IDOR, which appears in OWASP testing guidance and CWE-639. OWASP introduced BOLA through its API Security Top 10 and ranks it API1, making it the top API risk. That history explains the vocabulary. An API can expose an IDOR, and a web application can lack object-level authorization. Calling the same order swap by either name does not change what the server needed to check.

Where the vulnerability actually lives in the code

The vulnerable execution path accepts an identifier, fetches the object, and fails to verify that the caller may access it. The omission is at the third step. Authentication has already established who the user is, but identity alone grants no right to a particular order or invoice.

The hotel analogy makes the distinction plain. A key card opens the front door, then opens every room because nobody checks whether the card matches the room number. The failure is at the room. In code, the corresponding check belongs where the object is resolved, before the requested access proceeds.

For an invoice that must belong to the caller’s tenant, the short pseudocode pattern is if invoice.tenant_id != caller.tenant_id: raise Forbidden(). That check ties the fetched object to the authenticated caller. Tenant matching is not the whole policy for every application. The check may instead need to use identity, ownership, or another relationship that allows access to the object. The durable fix enforces that relationship at the service boundary on every object access.

Horizontal BOLA lets a user access another user’s object at the same privilege level. Vertical BOLA lets a user with lower privileges access a resource that requires higher privileges, crossing both ownership and privilege boundaries and so may cause more harm. Both start with access the caller should not have. However, the vertical case also exposes a failure in the role and privilege model.

Identifier design does not repair either failure. Numeric resource IDs are guessable and give testers an obvious starting point, but replacing them with UUIDs only reduces discoverability. A UUID that a user gets through a legitimate channel can still be used against an endpoint that has no ownership check. The flaw is a programming omission or inconsistent enforcement.

Why automated scanners structurally cannot find this class of flaw

A pattern-based scanner sees little wrong with the request that swaps the order. Its syntax is valid, the user is authenticated, and the server returns a well-formed HTTP 200 response. Nothing in that exchange identifies the rightful owner. Unless the scanner knows how the caller is related to the object, it cannot tell whether the response is allowed or leaks data.

BACFuzz names two things that make broken access control hard to detect automatically. The first is building a test oracle, a way to reliably tell whether a result is wrong, because authorization violations usually cause no crash and show no clear error. The second is generating valid, meaningful inputs that actually reach the authorization decision. Malformed requests often fail before they get that far. Crash-focused fuzzing looks for crashes, while BOLA is dangerous because the request succeeds without any sign of a failure.

The research also shows why “automation cannot help” would be too broad a conclusion. BACFuzz combines LLM-guided parameter selection, runtime feedback, and SQL-based oracle checking for web applications built with a particular server-side language. It detected the majority of known issues in a set of real-world applications and uncovered previously unknown vulnerabilities. Its scope is still narrow, however. It remains under peer review and is limited to applications backed by that language.

Static analysis cannot establish the runtime caller-object relationship from code alone, while dynamic application security testing with a single session lacks the comparison needed to identify another user’s resource. That is the structural constraint behind multi-session testing. A tester needs at least two identities and enough knowledge of the object model to know which access should fail. Whitebox or greybox access supplies context that an isolated request cannot.

How to test systematically: the multi-role, cross-session methodology

To address that limitation, testers should begin with multiple accounts and a structured authorization matrix. The account setup needs a same-tenant peer user, a cross-tenant stranger, and a lower-privilege role. The matrix pairs every object type with every role and records what access each role should have and what access it gets. Expectations must be clear before interpreting a response. Otherwise, a request that succeeds may look wrong without proving that it broke any rule.

The next step is to capture object references under an authorized or privileged session, then replay those references under a separate session. The tester evaluates any HTTP 200 by comparing the responses against the matrix. This makes the relationship test explicit. The object is known to belong to one identity or tenant, while the replay establishes what a different identity can do with it. Keeping both requests preserves the evidence needed to reproduce the result.

Read access is the first scenario to test. The tester uses User A’s session token to request User B’s resource identifier. A vulnerable API returns User B’s data, while the secured behavior in this scenario is HTTP 403. The response comparison must show the exposed fields. A changed identifier by itself proves only that a request was sent.

Write and delete access need their own tests because a read test does not show how those actions are protected. For write access, the tester substitutes an identifier to attempt a change to another user’s object. For delete access, the tester attempts to delete it. The consequences differ from a data leak. Modification and deletion can alter or destroy records the attacker does not own, so their severity must reflect the action.

Cross-tenant access and role ID manipulation complete the five scenarios. The cross-tenant test substitutes a resource identifier belonging to a completely separate tenant, rather than another user inside the same organization. The role test substitutes a higher-privilege role identifier to probe vertical BOLA and privilege escalation. These boundaries need their own evidence. A same-tenant peer test does not establish tenant isolation, and an ownership check alone does not prove that privileged resources are protected.

GraphQL changes how testers map this work. REST testing can be largely organized around identifier substitution in path parameters, while GraphQL requires field-level analysis because different combinations of fields can be queried. Property-level exposure can overlap with identifier and tenant-boundary failures. The comparison principle remains the same, however. The tester must check which fields each identity is allowed to retrieve, beyond judging access to the request as a whole.

Engagement type determines how much time goes into discovering that map. Blackbox testing starts with an external attacker’s information, so coverage is bounded by what the tester can discover within the allotted time. Whitebox access includes source code, cloud configuration, and documentation, which typically exposes more findings earlier. Greybox removes a particular bottleneck for BOLA testing. A supplied role matrix and API schema make the intended relationships visible, while leaving the tester to discover and prove the failures.

The tester still needs a working demonstration, with the request under Session A, the request under Session B, and diffed responses showing the unauthorized result. Documentation supplies the expected rule. The cross-session comparison proves that the rule holds or shows exactly where the check fails.

Why multi-tenant SaaS environments amplify the blast radius

In multi-tenant SaaS, objects that belong to different customers pass through the same code path. A missing ownership check in that shared path can therefore expose every record of the same type across tenants, rather than only the record used in the demonstration. The defect is shared across those objects.

Once an attacker finds that path, identifier iteration can turn access to one record into bulk harvesting at the speed of scripted HTTP requests. Guessable identifiers make that progression easier, but the underlying exposure remains the absent check. This changes the business stakes of the finding. A cross-tenant result puts in doubt the separation that customers count on when they put their data in a shared application.

Enterprise buyers then have questions beyond whether the endpoint was patched. They want to know whether their organization’s data was accessible and what changed in the architecture to prevent recurrence. Broken access control, tenant-boundary failures, and account takeover paths can stall or kill enterprise deals during security review. The testing evidence therefore affects both engineering priorities and procurement confidence.

The Cloud Security Alliance’s 2026 analysis found that AI-generated code was more likely than non-AI code to introduce IDOR/BOLA. Code-generation models can reproduce the fetch-by-ID pattern without the accompanying ownership check because they do not reason about the application’s object-ownership semantics. This is an amplifier of IDOR/BOLA risk. Producing more code with that omission increases the urgency of systematic authorization testing, especially where one implementation serves many tenants.

What a credible BOLA finding looks like in a pen test report

A credible finding gives the engineering team a reproducible failure. It shows the exact request under Session A, the exact request under Session B with the substituted identifier, and the full diffed responses demonstrating the leaked or changed object. The severity follows the demonstrated action and scope. Read, write, and delete access have different consequences, as do single-tenant and cross-tenant failures.

By contrast, a statement that object-level authorization may be missing on /api/orders/{id} remains an unverified possibility without a reproduced exploit. It does not establish which caller reached whose object or which access rule failed. An auditor cannot use it as demonstrated control failure, and a tester cannot replay it to establish that remediation worked.

The report should also include the authorization matrix produced during testing. That artifact shows the roles and object types covered, the combinations that returned unexpected access, and those that correctly denied it. Whitebox access makes it auditable because source code and the API schema allow the matrix to be validated against every defined endpoint.

Horizontal and vertical findings need separate documentation because their fixes can diverge. Horizontal BOLA calls for an ownership check, while vertical BOLA implicates the role and privilege model and may require architectural changes. The report must preserve that distinction. For SOC 2, HIPAA, and ISO 27001 purposes, the finding and its remediation together provide evidence that access control is tested and enforced. A report with no BOLA findings in a multi-tenant application deserves scrutiny of its coverage.

The practical demand is precise evidence of both failure and repair. A compliance-box report can name BOLA without showing whether the test meaningfully exercised object boundaries. A useful report gives engineers the caller, object, action, expected denial, and demonstrated result needed to fix and retest the defect. That is where the IDOR/BOLA distinction pays off, connecting the reference that exposed the flaw to the server-side rule whose enforcement must be proved.

Sources

  1. BACFuzz: Exposing the Silence on Broken Access Control Vulnerabilities in Web Applications
Filed underAccess Control

More in Access Control