Security Deep Dive
BOLA Vulnerability
The Architect's Guide to Preventing Broken Object Level Authorization
BOLA holds #1 on the OWASP API Security Top 10 for a simple reason: it needs no special tools to exploit. An attacker changes one number in a URL. Authentication passes. Authorization fails silently. The attacker reads data that isn't theirs.
What BOLA Is
BOLA — Broken Object Level Authorization, also called IDOR (Insecure Direct Object Reference) — occurs when an API accepts an object identifier from the client and returns that object without verifying the requester has rights to it.
The token is valid. The endpoint exists. But nobody checked whether this user owns this object.
Attacker authenticated as user 42 — requesting invoice owned by user 99GET /api/invoices/1047Authorization: Bearer <valid-token>HTTP 200 OK ← should be 403 Forbidden
Why Architects Miss It
Authentication and object-level authorization are separate concerns. Frameworks enforce authentication — they verify a token is present and valid. They do not verify that the authenticated user may access the specific object that token was used to request.
Teams add an authorization decorator to their routes and consider authorization done. It isn't. That check answers one question: is the user logged in? It says nothing about whether the user may access object 1047.
The gap lives in every endpoint that accepts an ID parameter and queries a database by that ID without filtering by the current user's identity.
Where BOLA Lives
Every route that exposes a direct object reference is a candidate:
GET /api/users/{id}/profile
PUT /api/orders/{id}
DELETE /api/documents/{id}
GET /api/accounts/{accountId}/transactions/{txId}
The nested route is the trap. You verify the account belongs to the user — but the transaction ID still accepts any value, including transactions from other accounts entirely.
The Fix: Verify Ownership After Authentication
Fetch the object, then compare its owner to the authenticated user. Reject the request if they don't match.
Vulnerableinvoice = db.find(id)return invoice
Fixedinvoice = db.find(id)if invoice.owner_id != current_user_idreturn 403 Forbiddenreturn invoice
Return 403 Forbidden when the object exists but the user lacks rights. Return 404 Not Found only when your threat model requires hiding whether an object exists at all.
Four Patterns That Prevent BOLA at the Architecture Level
1 — Filter at the repository layerBuild user_id into every data access query. A method named find_by_id_and_owner(id, user_id) makes the ownership check impossible to skip — it's required by the signature.
2 — Use resource-based authorization policiesMost frameworks support authorization handlers that receive the resource object itself, not just the route. Centralize the ownership logic there and call it from every handler that touches user-owned data.
3 — Replace sequential IDs with UUIDs in public routesSequential integers make enumeration trivial. UUIDs don't eliminate BOLA — the ownership check must still exist — but they raise the cost of accidental discovery and make automated scanning harder.
4 — Audit every object-level accessLog the requesting user_id, the target object ID, and the authorization outcome. A spike in 403s on a single endpoint is your first signal of active exploitation.
Automated Detection
How ApiPosture Pro Catches BOLA Before Production
The AP101 — Broken Access Control rule goes beyond checking for an authorization attribute on the route. It reads actual ASP.NET Core method body source code and flags the patterns that create BOLA:
›Database writes without authorization — public endpoints writing to the database with no authorization check in the method body.
›IDOR without ownership checks — data access by ID where the method body shows no ownership verification pattern.
›GET endpoints that perform destructive operations — HTTP method violations that bypass CSRF protection meant to guard state changes.
›Missing audit logging on DELETE — caught by AP107, because silent destructive operations make post-incident investigation impossible.
All analysis runs 100% locally — no code leaves your machine. Add apiposture-pro scan . --fail-on high to your CI/CD pipeline to block merges that introduce BOLA-prone patterns before they reach production.