Join our Newsletter — 33% off our NHI Course
Home› Guides› BOLA vs BFLA: Where Each API Authorisation Check…
Guide Web & API Security

BOLA vs BFLA: Where Each API Authorisation Check Must Live

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 14 November 2026 14 min read
On this page

Broken object level authorisation and broken function level authorisation are both "the API let me do something I should not", but they fail in different layers, are found with different tests and are fixed by different owners. BOLA (OWASP API1:2023) is a caller reaching another party's record through an endpoint they are allowed to use. BFLA (OWASP API5:2023) is a caller reaching an operation, often administrative, that their role should never reach at all. Treating them as one bug class leads to fixes in the wrong place: role checks that do nothing for BOLA, or per-record checks that leave admin routes open. This guide is for API developers, security architects, testers and assessors. It explains the mechanics side by side, where each check must live, how to test and detect each, and how machine clients and token scopes change the picture. Each risk has a deeper page: OWASP API Top 10 API1 Broken Object Level Authorization Guide and OWASP API Top 10 API5 Broken Function Level Authorization Guide.

Key takeaways

  • BOLA is about which record, BFLA is about which operation. OWASP says that in BOLA the user is meant to have access to the endpoint and the violation happens at the object level by manipulating the ID; reaching an endpoint they should not is BFLA.
  • The checks live in different places. Function checks belong at the route, controller or policy layer, deny by default. Object checks need the record and its owner or tenant, so they belong next to the data access.
  • Comparing a token user ID with a URL parameter is not enough for BOLA. OWASP API1:2023 states this covers only a small subset of cases; the check must ask whether this subject may perform this action on this specific record.
  • They are tested differently. BOLA testing swaps object identifiers between two accounts at the same privilege level. BFLA testing replays requests from a lower role against higher-privilege functions, other HTTP methods and undocumented routes.
  • Machine clients make both worse. A service token with broad scopes and no user subject turns every object check into "trust the parameter", and an over-scoped client can call admin functions it was never meant to.

The short answer

If a caller changes an identifier (an order number, a VIN, a shop name, a document key) and gets someone else's data or changes someone else's record, through an operation they are legitimately allowed to call, it is BOLA. If a caller changes the operation (a different path, HTTP method or GraphQL mutation) and gets functionality reserved for another role, it is BFLA. Fix BOLA with a per-request, per-object authorisation decision based on the authenticated subject and the record's owner, tenant or relationships. Fix BFLA with a central, deny-by-default function authorisation layer that every route passes through. Most real APIs need both, and one request can trip both, for example a regular user calling an admin delete endpoint on another tenant's record.

Side-by-side comparison

DimensionBOLA (API1:2023)BFLA (API5:2023)
Question the check answersMay this subject act on this specific object?May this subject call this operation at all?
Escalation directionHorizontal: peers at the same privilege levelVertical: a lower role reaching a higher role's function
What the attacker changesObject identifier in path, query, header or bodyEndpoint path, HTTP method, or operation name
Endpoint legitimately available to caller?YesNo
Where the check must liveData access layer, or a policy call that receives the loaded recordRoute, controller or gateway policy, before business logic runs
Inputs the decision needsSubject, action, object owner, tenant or relationshipSubject, role or group, operation
OWASP rating (2023)Exploitability easy, prevalence widespread, detectability easy, technical impact moderateExploitability easy, prevalence common, detectability easy, technical impact severe
Closest CWECWE-639 Authorization Bypass Through User-Controlled KeyCWE-285 Improper Authorization (mapping discouraged; CWE-862 or CWE-863 preferred)
OWASP ASVS 5.0V8.2.2 data-specific accessV8.2.1 function-level access
Typical impactData disclosure, modification or deletion across users or tenants; sometimes account takeoverAdmin actions, privilege escalation, bulk data export, service disruption

Mechanics and request examples

BOLA in practice

OWASP's API1:2023 scenarios show the pattern. An e-commerce platform serves revenue charts from /shops/{shopName}/revenue_data.json, and another endpoint lists all shop names, so substituting names exposes thousands of stores' sales data. A vehicle API accepts a VIN to start engines and unlock doors but never checks that the VIN belongs to the signed-in user. A GraphQL deleteReports mutation deletes whatever document keys it is given. In each case the caller is authenticated and the operation is one they use every day; only the object reference is foreign. OWASP notes that identifiers can be sequential integers, UUIDs or strings, and that the server response usually tells the attacker whether it worked.

Random, unguessable IDs help but do not fix BOLA. OWASP recommends random GUIDs as a measure, and the OWASP Authorization Cheat Sheet is explicit that obscuring or randomising IDs is not sufficient by itself: IDs leak through logs, shared links and other endpoints. CWE-639 lists Insecure Direct Object Reference (IDOR) as an alternate term, while noting the OWASP IDOR concept is broader.

BFLA in practice

OWASP's API5:2023 scenarios: a mobile app calls GET /api/invites/{invite_guid}, and an attacker changes the method and path to POST /api/invites/new with a role of admin, an endpoint meant only for the admin console that has no function check. In a second case GET /api/admin/v1/users/all returns every user's details to anyone who guesses the path. OWASP warns not to assume an endpoint is regular or administrative from its URL, because admin functions often sit beside regular ones under paths like /api/users. It also lists method changes, such as GET to DELETE, as a test question.

Where each check must live

  • Function checks (BFLA): one consistent authorisation module, invoked by every business function, that denies by default and requires explicit grants of roles or permissions per operation. OWASP suggests admin controllers inherit from an abstract admin controller that performs role checks, and that admin functions inside regular controllers check role explicitly. An API gateway or external policy decision point can enforce coarse route and method rules, but the service must still enforce them, because internal callers can bypass the gateway.
  • Object checks (BOLA): need the record's owner, tenant or relationships, which only exist once you know which record. Two patterns work: scope the query itself by the subject (for example, every repository method takes the tenant and user from the verified token, never from the request), or load the object and pass it to a policy call such as can(subject, "update", invoice). The OWASP Authorization Cheat Sheet recommends deriving objects from the authenticated identity where possible and checking access to the specific object on every request.
  • Trusted layer only: OWASP ASVS 5.0 V8.3.1 requires authorisation at a trusted service layer, not in client code. Hiding a button in the UI is not a function check.
  • Model choice: role-based access control handles BFLA well. Object decisions usually need attributes or relationships; the OWASP cheat sheet notes RBAC struggles with object-level and multi-tenant decisions and prefers ABAC or ReBAC. See the Authorisation Models Guide and Policy-as-Code for Authorisation Guide.
  • Field level is a third layer: returning or accepting fields a caller should not see or set is API3:2023 Broken Object Property Level Authorization, a separate check (ASVS V8.2.3).

Testing each, from the assessor's side

AspectBOLA testingBFLA testing
Accounts neededAt least two accounts with the same role, ideally in two tenantsOne account per role, from anonymous to the highest non-admin, plus an admin for reference
Core techniqueReplay each object-taking request from account A with account B's identifiers, for every methodReplay higher-role requests with lower-role tokens; try other methods on known routes; probe documented but unlinked routes from the API specification
Coverage sourceEvery endpoint that accepts an ID in path, query, header or body, including nested and batch IDsThe full route and method inventory from the OpenAPI or GraphQL schema, compared with the role matrix
Pass conditionForeign objects return 403 or 404 consistently, with no data and no side effectDisallowed operations return 401 or 403 before any business logic runs
AutomationPaired-user integration tests seeded with known cross-user objectsMatrix-driven tests: one test per role calling every service

The OWASP Authorization Testing Automation Cheat Sheet describes the BFLA side well: keep an authorisation matrix of features, roles and expected allowed or denied responses, generate one integration test per role that calls every service, and run it on every release because authorisation regressions arrive with feature changes. Extend the same matrix with a data dimension (own object, peer object, other tenant's object) to cover BOLA. These tests catch regressions; they do not replace an independent assessment. See the API Penetration Testing Guide for scoping.

Detection signals in API logs

Log the fields that make both visible: authenticated subject, client ID, tenant, role, route template (not just raw path), HTTP method, object identifiers, response code and response size. The OWASP Authorization Cheat Sheet asks for consistent, parseable formats with enough detail to investigate, without logging sensitive data. NIST SP 800-53 AC-6(9) asks for logging the use of privileged functions, which is the BFLA audit trail.

  • BOLA signals: one subject touching an unusual number of distinct object IDs on a route; sequential or enumerated IDs; a high ratio of 403 or 404 to 200 for one subject on object routes; successful reads of objects whose owner or tenant differs from the caller (only visible if the service logs owner or tenant on access).
  • BFLA signals: non-admin subjects calling admin route templates; methods never seen for a route from that role; 403 bursts across many routes from one subject, which suggests route probing; any 2xx on an admin function from a non-admin role, which should page someone.
  • Both: baseline normal calls per role and per client, and alert on deviation. Feed API gateway and application logs to the SIEM with the same subject identifiers.

Machine clients and token scope

Service accounts and OAuth clients are frequent BOLA and BFLA paths because their tokens often have no user subject. When a backend calls an API with a client credentials token and passes user_id=123, the API can only check that the client is trusted, so any compromise of that client is BOLA across every user. OWASP ASVS 5.0 V8.3.3 requires access to be based on the originating subject's permissions, not an intermediary's. Carry the user through with token exchange instead; the Authorisation Code vs Client Credentials Flow guide covers grant choice.

Scopes are function-level controls. A scope like orders:read stops a client calling orders:delete, which is BFLA prevention, but says nothing about which orders. Do not let scope checks stand in for object checks. For machine clients, give each integration its own client, map scopes to specific operations, keep admin scopes off integration clients, and tie each client to a tenant so object checks can still filter by tenant. See the OAuth Scope Design Guide and Machine-to-Machine OAuth (Client Credentials) Guide. AI agents calling APIs through tools inherit the same rules: the API, not the agent, must make the object decision.

Worked scenario: a multi-tenant billing API

A billing SaaS exposes GET /v2/invoices/{id}, POST /v2/invoices/{id}/refund and, for support staff, POST /v2/admin/tenants/{tenant}/credit. A review finds three problems. First, the invoice query used only the ID, so a customer with a valid token could read any tenant's invoices: BOLA. Second, the refund route checked the billing:write scope but not that the invoice belonged to the caller's tenant: BOLA through a write. Third, the admin credit route lived in the same controller and checked only that the caller was authenticated: BFLA.

The fix split ownership. The platform team moved route rules into a policy file loaded by every service, denying any route without an explicit role or scope grant, and moved admin routes into a controller that requires the support role and logs every call. The billing team changed the repository so every query takes the tenant from the verified token, and added a policy call on refunds that checks tenant and refund limits on the loaded invoice. A matrix test suite now runs three roles against every route and two tenants against every object route on each build.

Implementation steps

  1. Inventory routes and methods: generate the list from the OpenAPI or GraphQL schema and from gateway logs, to catch undocumented routes.
  2. Write the authorisation matrix: for each route and method, the roles or scopes allowed and whether it takes object identifiers. This is the documentation ASVS V8.1.1 asks for.
  3. Centralise function checks: one middleware or policy layer, deny by default, with admin functions grouped and separately protected. Start in log-only mode to see what would be denied, fix legitimate gaps, then enforce.
  4. Add object checks per data path: scope queries by tenant and subject from the token, add policy calls for actions that need more context, and return 404 or 403 consistently for foreign objects.
  5. Automate tests: matrix tests per role and paired-account tests per object route, as release gates. Roll back a policy change by reverting the policy file, which is easier when policy is code.
  6. Instrument and alert: add owner and tenant to access logs and set the detection rules above.

Framework mapping

FrameworkBOLABFLA
OWASP API Security Top 10 2023API1:2023 Broken Object Level AuthorizationAPI5:2023 Broken Function Level Authorization
OWASP ASVS 5.0V8.2.2; V8.4.1 cross-tenant controlsV8.2.1; V8.4.2 administrative interfaces
CWECWE-639CWE-862, CWE-863 (children of CWE-285)
NIST SP 800-53 Rev 5AC-3 Access Enforcement; AC-24 Access Control DecisionsAC-6 Least Privilege; AC-6(9) Log Use of Privileged Functions
NIST SP 800-53 Rev 5 (both)SA-11 Developer Testing and Evaluation; AU-6 Audit Record Review, Analysis, and Reporting
NIST CSF 2.0 (both)PR.AA-05 access permissions defined, managed, enforced and reviewed with least privilege
MITRE ATT&CK v20 (both)T1190 Exploit Public-Facing Application, where the API is internet facing

Common failure patterns

  • Fixing BOLA with role checks: adding @RequireRole("customer") to an object route; every customer still reaches every customer's records.
  • Trusting the gateway alone: route rules at the edge, none in the service, so internal callers and new routes skip them.
  • Checking only reads: object checks on GET but not on PUT, DELETE, batch or export routes.
  • Relying on unguessable IDs: UUIDs treated as access control, then leaked through list endpoints, URLs and logs.
  • Admin functions in regular controllers: a support or export function added beside customer routes without its own role check.
  • Service tokens with user ID parameters: a machine client acting for users by passing an identifier the API cannot verify.

Practitioner checklist

  • Classify every authorisation finding as object, function or property level, and route it to the right owner.
  • Keep a role and route matrix, derived from the API schema, under version control.
  • Enforce function checks centrally, deny by default, inside each service as well as at the gateway.
  • Scope every data query by the tenant and subject from the verified token, never from request parameters.
  • Check object access on every method, including writes, deletes, batch and export endpoints.
  • Run matrix tests per role and paired-account tests per object route on every build.
  • Log subject, client, tenant, route template, method, object ID and outcome; alert on admin route use by non-admins and on ID enumeration.
  • Give machine clients their own narrow scopes and carry user context with token exchange, not ID parameters.

Standards and references

Related NHI Mgmt Group resources: OWASP API Top 10 API1 Broken Object Level Authorization Guide, OWASP API Top 10 API5 Broken Function Level Authorization Guide, API Penetration Testing Guide, Authorisation Models Guide.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 14 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org