What is BOLA (broken object level authorization)?
BOLA, broken object level authorization, is an API that accepts an object ID from the caller and returns or changes that object without checking the caller is allowed to. It is the API name for IDOR, and the OWASP API Security Top 10 2023 ranks it as the first risk, API1.
Why it matters
Modern front ends talk to APIs, and APIs pass object IDs everywhere: in the path, in the query string, in JSON bodies. OWASP's explanation of API1:2023 points out that every endpoint receiving an ID needs its own object-level check, and that this check is easy to forget because the endpoint works perfectly for the honest user who only ever asks for their own objects.
BOLA and IDOR describe the same flaw from two angles. IDOR names the mechanism, a direct reference to an object that the attacker can change; BOLA names the missing control, authorization at the level of a single object. Use whichever your audience knows; the test and the fix are the same.
Example: how to test your own API for BOLA
Run this on your own API (https://your-app.example) or on CyberGym, the legal practice target, never on someone else's. You need two accounts you control, A and B, and the list of endpoints that take an ID.
1. As user A, create an object: an order, a note, an uploaded file. Record its ID and the exact request that reads it.
2. Replay that request with user B's session token and A's object ID. A correct API answers 403 or 404. If it answers 200 with A's data, that endpoint has BOLA.
3. Repeat for the write methods on the same object, and for IDs that sit in JSON bodies rather than the URL:
GET /api/orders/1042 Authorization: Bearer <token of B> -> expect 403/404
PATCH /api/orders/1042 {...} Authorization: Bearer <token of B> -> expect 403/404
POST /api/invoices/download {"orderId": 1042} (token of B) -> expect 403/404
The fix belongs in the code that loads the object: look it up by ID and by the caller's identity together, or check ownership right after loading, and return the same error for 'not yours' as for 'does not exist' so the response does not confirm which IDs are real.
Common mistakes
- Authorizing the endpoint instead of the object. Being allowed to call /api/orders/ does not mean being allowed to read order 1042.
- Trusting an ID because the client sent it in a token or hidden field. Anything in the request can be edited. Take the user from the session, not from the body.
- Testing only GET. Updates and deletes across users are the same bug, with more damage.
- Assuming GraphQL or gRPC is different. Any API that takes an object identifier needs the same check, whatever the transport.
Related terms
Go deeper
Sources
Test only sites you own or have written permission to test. To practise without one, use CyberGym, a legal, deliberately vulnerable target. Practise on CyberGym.
