BOLA: Testing Object-Level Authorisation in APIs

A hands-on methodology for finding broken object-level authorisation across REST and GraphQL APIs, with a focus on authorisation decisions rather than parameter guessing.

USER AAuthenticatedObject 1001AllowedObject 1002Test targetUSER AExpected: allowUSER B / TENANT BExpected: denyThe authorisation decision must happen at the object boundary

PoCForge technical illustration · conceptual attack path for educational testing.
Table-style object map for BOLA testing with object types owners and actions
Map object types, IDs, owners and sensitive actions before mutating requests.
Side-by-side comparison of expected authorisation versus BOLA vulnerability
BOLA is a missing server decision when object 1002 is returned to the wrong principal.

Broken Object Level Authorization (BOLA) occurs when an API accepts a request for a specific object without correctly checking whether the caller is allowed to access that object. It is one of the most important authorisation tests because the application may appear perfectly authenticated while still exposing another user’s data.

The core test is simple: change the object reference while keeping the authenticated identity the same. The hard part is doing this systematically across the application’s object graph.

Authorisation is not authentication.An API can correctly identify User A and still incorrectly allow User A to read, modify or delete an object owned by User B.

Build an object map before attacking

Start by identifying object identifiers and relationships: user IDs, account IDs, order IDs, document IDs, project IDs, message IDs, invoice IDs, UUIDs and nested resource paths. Record which roles and tenants should be able to access each object.

USER AAuthenticatedObject 1001AllowedObject 1002Test targetUSER AExpected: allowUSER B / TENANT BExpected: denyThe authorisation decision must happen at the object boundary

Illustrative BOLA test: User A is authorised for object 1001 but should be denied access to User B’s object 1002.

A repeatable test pattern

  1. Authenticate as User A.
  2. Perform a legitimate request for an object User A owns.
  3. Capture the request and identify the object reference.
  4. Replace the reference with an object belonging to User B or another tenant.
  5. Compare status code, response body, side effects and secondary API calls.
  6. Repeat with read, update and delete operations.

Do not stop at numeric IDs

UUIDs, opaque tokens and encoded identifiers can make enumeration harder, but they do not implement authorisation. If you can obtain another valid identifier through a list endpoint, notification, browser history, mobile response or predictable workflow, the authorisation check still matters.

REST and GraphQL variations

REST testing often focuses on path and body parameters such as /api/orders/1234 or {"orderId":1234}. GraphQL adds another layer: object references can be embedded inside queries, mutations, variables or nested resolver arguments. Test each resolver independently because a secure parent object does not guarantee secure child-object authorisation.

Interactive: expected vs. vulnerable behaviour

BOLA decision stagesPOCFORGE / INTERACTIVE

Keyboard: ← → · Respects reduced-motion (no autoplay).

Change the requested object

Expected behaviour: the server verifies that User A is authorised for object 1001 before returning or changing it.

Authorisation test matrix

Operation Same user Other user Other tenant
GET Allow Deny unless explicitly shared Deny
PUT / PATCH Allow if role permits Deny Deny
DELETE Allow if role permits Deny Deny
Nested object Allow if parent + child authorised Deny Deny

What strong authorisation looks like

Enforce authorisation server-side at the point where the object is accessed. Prefer policy checks based on authenticated identity, tenant, role and object ownership. Avoid relying on hidden fields, client-side controls, object ID secrecy or UI restrictions.

For sensitive operations, log the authorisation decision and test negative cases as part of automated integration testing. A regression suite should include cross-user and cross-tenant access attempts.

Further reading

OWASP’s API Security Project covers object-level authorisation as a central API security concern. OWASP API Security Project.

Related research: API authorisation attack chains · API security testing.

Frequently asked questions

What is BOLA?

Broken Object Level Authorization: the API fails to verify that the caller is allowed to act on the specific object identified in the request.

Does changing an ID prove BOLA?

Only if the server returns or modifies another principal’s object without an authorisation check. Guessing IDs alone is not the finding—the missing decision is.

Does BOLA apply to GraphQL?

Yes. Resolvers and nested fields need object-level checks just as REST path parameters do.

How do you reduce false positives?

Use two authenticated roles or tenants, confirm ownership expectations, and document the exact failed control.

← All researchDiscuss an assessment →