The anatomy of a BOLA vulnerability

Broken Object Level Authorization (BOLA), formerly known as IDOR, occurs when an application provides direct access to objects based on user-supplied input without verifying if the user has permission to access that specific object.

Consider a typical fintech API endpoint to view a transaction receipt:

GET /api/v1/transactions/4582

If User A is logged in and changes the transaction ID in the URL to `4583`, and the server returns User B's transaction details, you have a critical BOLA vulnerability. The server successfully authenticated User A (they have a valid JWT), but it failed to authorize whether User A owned object `4583`.

Predictable IDs

Using sequential integers for database primary keys makes BOLA trivial to exploit. An attacker can write a script to iterate from `1` to `100,000` and download your entire user database.

Missing Ownership Checks

The root cause: the controller fetches the database record using the requested ID but fails to assert `record.user_id === current_user.id` before returning the JSON payload.

Hidden Endpoints

BOLA often hides in secondary endpoints, like `/api/v1/users/{id}/kyc-documents` or `/api/v1/receipts/{id}/pdf`, where developers forget to apply the same strict middleware used on the main endpoints.

How to fix BOLA permanently

1. Implement authorization middleware

Do not rely on developers remembering to write `if (record.owner_id !== user.id)` in every single controller method. Implement a centralized authorization policy engine (like Pundit in Ruby or Casbin in Node.js) that enforces ownership checks at the middleware layer before the controller logic executes.

2. Transition to unpredictable IDs (UUIDs)

Migrate your primary keys from auto-incrementing integers to UUIDv4. While this does not fix the authorization flaw, it mitigates the risk of enumeration attacks. An attacker cannot easily guess `123e4567-e89b-12d3-a456-426614174000`.

3. Rely on the session context, not the client

Never trust the client to tell you who they are. If an endpoint requires the current user's ID, do not accept it as a URL parameter or JSON body field:

Vulnerable: {`POST /api/v1/transfer {"from_account": 123, "amount": 5000}`}

Secure: {`POST /api/v1/transfer {"amount": 5000}`} (The backend determines the from_account by parsing the authenticated user's JWT).

Are your API endpoints leaking data to authenticated attackers?

Book an API Penetration Test

Testing for BOLA in your CI/CD pipeline

Automated vulnerability scanners (DAST) struggle to find BOLA because they don't understand the context of object ownership. To catch this in your pipeline, you must write specialized integration tests.

For every endpoint that fetches an object by ID, write a test that creates an object belonging to `User A`, then authenticates as `User B` and attempts to fetch it. Assert that the response is a `403 Forbidden` or `404 Not Found`. If it returns a `200 OK`, the build must fail.

The Cost of BOLA

Regulatory repercussions

If a BOLA vulnerability allows an attacker to scrape thousands of KYC records or BVNs, you are facing a massive data breach. Under the NDPA and CBN frameworks, this triggers mandatory breach notifications and potentially severe financial penalties.

Related reading

Blog: The Most Dangerous API Vulnerability · Secure Your Fintech API

Services: API Security · Secure Architecture Review

Frequently asked questions

{faqs.map((faq) => (
{faq.q}

{faq.a}

))}