BOLA vs BFLA: the API authorization flaws scanners miss
Authorization, not injection, is what breaks most modern APIs. The two flaw classes that do the damage, BOLA and BFLA, are invisible to a scanner, because a scanner has no concept of who should be allowed to do what. Here is the difference between them, why pattern matching cannot find either, and how to actually test for both.
Planck Proof · Offensive Security Team · Updated September 13, 2026 · 8 min read
Look at almost any serious API breach of the last few years and you will find the same root cause: not a clever injection payload, but a missing authorization check. Someone requested an object that was not theirs, or called a function they should never have reached, and the server handed it over. These are the two classes at the top of the OWASP API Security Top 10, BOLA at number one and BFLA at number five, and together they account for the majority of real-world API compromise.
They are also the flaws your scanner will never report. Understanding why starts with knowing exactly what each one is.
What is BOLA (Broken Object Level Authorization)?
BOLA is a failure to check that the user asking for an object is allowed to have that specific object. APIs expose objects by identifier, /orders/124, /users/89/profile, /documents/abc-123, and the vulnerability is simple: the endpoint authenticates you (it knows you are a logged-in user) but never verifies that order 124 belongs to you before returning it.
So an attacker logs in with their own account, sees a request for GET /orders/124, and simply changes the number: GET /orders/125, 126, 127. If the server returns each one, they can walk the entire order table, other customers' addresses, amounts, and items, without ever touching an admin function. If you have heard this called IDOR (insecure direct object reference), it is the same bug; OWASP renamed it BOLA for the API context. Identifiers do not have to be sequential integers, either. UUIDs assumed to be unguessable, references buried in a request body, and IDs resolved through nested GraphQL fields are all BOLA surface.
What is BFLA (Broken Function Level Authorization)?
BFLA is a failure to check that the user is allowed to perform that action at all. Where BOLA is about data you should not see, BFLA is about functions you should not be able to call. A standard user finds the admin routes, DELETE /users/89, POST /admin/refunds, PUT /accounts/settings/global, and simply calls them with their ordinary session token. If the server executes the request because it only checked that you are logged in, not which role you hold, that is BFLA.
It often hides behind the client. The admin button is not rendered in your UI, so the assumption is that you cannot reach the function, but the API endpoint is still live, and nothing stops you from calling it directly. Switching an HTTP method on the same path (GET to DELETE), guessing an undocumented admin route, or invoking a gRPC service method the client was never meant to expose are all ways BFLA shows up.
BOLA vs BFLA: the difference in one line
The quickest way to keep them straight: BOLA crosses between accounts at the same level; BFLA crosses between levels. BOLA is a regular user reaching another regular user's data. BFLA is a regular user reaching an administrator's powers.
| Dimension | BOLA | BFLA |
|---|---|---|
| OWASP API rank | API1 (2023) | API5 (2023) |
| What fails | Object ownership check | Role / privilege check |
| Attacker gains | Another user's data | A function above their role |
| Boundary crossed | Between peer accounts | Between privilege levels |
| Classic example | GET /orders/{other_id} | DELETE /users/{id} as a normal user |
| Also known as | IDOR | Privilege escalation, forced browsing |
| How to catch it | Replay one account's request as another | Replay a low-privilege token against privileged routes |
Some findings are both at once: an endpoint that is both admin-only and object-scoped can fail on either axis, which is why real testing checks each dimension separately on every operation.
Why scanners miss both
A vulnerability scanner or DAST tool works by firing payloads at inputs and matching responses against a library of signatures. That model is fundamentally blind to authorization, for one reason: authorization is relative. There is nothing wrong with the response to GET /orders/124 in isolation, it is a perfectly valid 200 with a valid order. Whether it is a vulnerability depends entirely on who asked. A scanner sees one request, one response, one identity. It cannot express the question that defines BOLA and BFLA: “should this user be allowed to do this?”
To answer that, you need at least two accounts and a way to compare them, to take a request that is legitimate for user A and replay it as user B, then check whether the server wrongly allows it. That is a stateful, identity-aware, multi-account exercise. It is exactly the shape of testing a signature engine cannot do, which is why these flaws sail straight through automated scans and land in production.
How to actually test for BOLA and BFLA
The method is conceptually simple and mechanically demanding. You authenticate as two or more user types, at minimum two peer accounts (for BOLA) and one low-privilege plus one high-privilege account (for BFLA). Then, for every operation the API exposes:
- For BOLA: take every request that references an object, in the path, a query parameter, or the body, and replay it with the other account's session, substituting object identifiers across accounts and tenants. If account B receives account A's object, that is a confirmed BOLA.
- For BFLA: take every privileged or admin function and call it with the low-privilege token, including method swaps on the same path and routes that are not exposed in the UI. If the action executes, that is a confirmed BFLA.
Doing this by hand across a real API, dozens or hundreds of operations, each with multiple parameters, times several role pairings, is enormous, repetitive work, which is why it so often gets sampled rather than done completely. This is where an agentic API penetration test fits the problem exactly. You provide one bearer token per user type; the agent parses your OpenAPI spec, enumerates every operation, and replays one role's requests as another across the whole surface. Because it is an agentic pentester rather than a scanner, it does not stop at “this looks off”, it confirms the cross-account access actually happened and reports it with the exact request and response that prove it, rated with a CVSS v3.1 vector.
Authorization is the part of API security that pattern matching cannot reach and that manual testing rarely covers exhaustively. Testing it well means treating every endpoint as a question about identity, and answering that question with more than one account. Anything less leaves the most common path into your data untested.
When BOLA and BFLA chain together
The two flaws are often described as separate categories, but in a real attack they frequently chain into a single path, and the chain is usually more damaging than either flaw alone. The common pattern: a BFLA-exposed admin function returns a list or export of objects, and the identifiers in that response become the fuel for a follow-on BOLA read against a completely different endpoint.
A standard user should never reach an admin listing endpoint at all. If that endpoint has a BFLA flaw, that is, it only checks that the caller is authenticated and never checks their role, the attacker gets back a page of records: customer IDs, order IDs, account numbers, whatever the export is built to return. On its own, that response is already a finding. But those identifiers rarely stop there. They are exactly what a second, ordinary-looking endpoint needs to serve up full records one at a time, an endpoint that authenticates correctly but never checks object ownership, a textbook BOLA.
An illustrative request sequence makes the chain concrete:
- Step 1, BFLA (privilege escalation):
GET /admin/customers/exportcalled with a standard user's token. The endpoint checks only that a valid session exists, not the caller's role, and returns a paginated list of customer IDs. - Step 2, harvest: the response body yields object identifiers, for example
customer_id: 8841, 8842, 8843, that the standard user was never meant to see. - Step 3, BOLA (object access):
GET /customers/8841/profile, then8842, then8843, replayed with the same standard user token against a separate profile endpoint that checks authentication but never checks whether the requested customer belongs to the caller. Each call returns full profile data for a customer the attacker has no relationship to.
Illustrative example, not a specific customer result.
Neither endpoint individually looks catastrophic in isolation: the export could be dismissed as a lower-severity access control gap, and the profile read could be mistaken for working as designed since it does return a valid record for a valid ID. The severity only becomes clear once you see the two steps as one path, an unauthorized function that manufactures the exact identifiers an unrelated authorization gap needs. This is also why testing endpoints independently, the way a scanner or a checklist audit does, misses the real risk. An agentic pentester that walks the full call graph, treats output from one operation as candidate input to the next, and replays actual session tokens across the chain is what surfaces this class of finding, and it hands you the two-step request sequence above as the reproduction, not just a pair of unrelated low and medium severity tickets.
References
Watch the agent replay one role as another
This is the Operator console running exactly the test described above: cross-account BOLA on object identifiers, then BFLA on admin-only functions called with a low-privilege token. Illustrative demo against api.example.com, the requests, sessions, and confirmations are what a real run streams.
Common questions
What is the difference between BOLA and BFLA?
BOLA (broken object level authorization) is about data: a user accesses another user's object, such as requesting GET /orders/124 when order 124 belongs to someone else. BFLA (broken function level authorization) is about actions: a user invokes a function or role they should not reach, such as a standard user calling an admin-only endpoint. BOLA crosses the boundary between accounts at the same privilege level; BFLA crosses the boundary between privilege levels.
Is IDOR the same as BOLA?
Largely yes. IDOR (insecure direct object reference) is the older name for the same class of bug. OWASP formalized it as BOLA, the number one risk in the API Security Top 10. BOLA is the term used for APIs, where object identifiers in the URL path or request body are the most common way the flaw appears.
Why can't vulnerability scanners find BOLA and BFLA?
A scanner tests one request at a time against a signature and has no concept of identity or roles. BOLA and BFLA are only visible when you compare what one user can do against what another user should be allowed to do, which requires at least two authenticated accounts and replaying one role's requests as another. Pattern matching cannot express that.
How do you test an API for BOLA and BFLA?
You authenticate as two or more user types, then for every endpoint that accepts an object identifier or exposes a privileged function, you replay one role's request as another and check whether the response leaks data or performs the action. An agentic pentester does this across every documented operation and reproduces each finding with the exact cross-account request and response.
How do you test for BOLA vs BFLA?
The mechanics differ by what you swap. For BOLA, you keep the same endpoint and role but substitute a different account's object identifier in the path, query, or body, then check if the response returns that account's data. For BFLA, you keep the same endpoint and identifier but substitute a lower-privilege token, then check if the privileged action still executes. Testing both means running each substitution across every operation in the spec.
Which is more dangerous: BOLA or BFLA?
Neither is universally worse; severity depends on what the object or function controls. A BOLA on a payment record can be as damaging as a BFLA on an admin panel, and a BFLA that only exposes a settings toggle may be lower risk than a BOLA that leaks medical records. Rate each finding by what it actually exposes, in context, rather than by which OWASP category it falls under.
What is the difference between IDOR and BOLA?
There is no technical difference; BOLA is the name OWASP gave IDOR (insecure direct object reference) when it formalized the API Security Top 10, and object-level authorization is the more precise description of the underlying failure. IDOR is still the term most engineers use in conversation. See BOLA vs IDOR for the full naming history and a worked example.
Is BFLA the same as BOLA?
No. Both are broken authorization, but they fail on different axes. BOLA fails an object-ownership check: a user reaches another user's data at the same privilege level. BFLA fails a role check: a user reaches a function reserved for a higher privilege level, such as an admin-only endpoint. An endpoint can be vulnerable to one, both, or neither, so each has to be tested independently.
Related
BOLA vs IDOR
The other naming question: is BOLA just IDOR renamed? The difference, and the request that proves it.
Read → GuideAgentic API penetration testing
Spec-driven testing of every operation, with cross-account BOLA and BFLA at its core.
Read → BlogAgentic pentesting vs DAST
Why a signature scanner and a reasoning agent are different tools doing different jobs.
Read → BlogHow agentic pentesting proves an exploit
Inside proof-based validation: why every finding is reproduced before it reaches you.
Read →Test what your API actually authorizes
Give Operator your spec and a token per role. It will replay one role as another across every operation, and prove what it finds.