API Security in Depth · API Threat Landscape & Object-Level Risks

Broken Object Level Authorization (BOLA)

The #1 API risk: checking that the caller may access this specific object.

BOLA (a.k.a. IDOR) happens when an endpoint takes an object ID from the request and fetches it without checking that the caller may access that object. Authentication alone doesn't help — the attacker is a valid user. Fix it structurally: scope queries by owner/tenant (WHERE id = :id AND tenant_id = :tenant), centralize policy checks, and test cross-user access automatically for every endpoint. Random IDs (UUIDs) reduce enumeration but are not authorization.

Ways to enforce object-level access

Approach Strength Weakness
Check in each handler Explicit Easy to forget one endpoint
Scoped repository (tenant/owner in every query) Hard to bypass Needs discipline in raw queries
Policy engine (OPA/Cedar/Oso) Central, auditable Integration effort; still must be called
Database row-level security Defense in depth Requires per-request DB session context
Unguessable IDs Slows enumeration Not authorization (IDs leak via URLs, logs, shares)
@router.get("/v1/orders/{order_id}")
async def get_order(order_id: UUID, user: User = Depends(current_user), db=Depends(session)):
    order = await db.scalar(
        select(Order).where(Order.id == order_id, Order.account_id == user.account_id))
    if order is None:
        raise HTTPException(404)          # same response for "missing" and "not yours"
    return OrderOut.model_validate(order)

Common pitfalls

  • Fetching by ID then checking ownership only in some code paths.
  • Trusting tenant IDs from the request body or path over the token.
  • Returning 403 vs 404 differently and revealing existence.

Key points

  • Scope every query by owner/tenant
  • Automate cross-user tests
  • IDs are not secrets

Further reading: OWASP API1:2023 BOLA

Practice questions

Why don't UUIDs fix BOLA?

Answer

They make guessing harder, but IDs leak through URLs, logs, shared links and other responses; access must still be checked against the caller.

How do you test for BOLA systematically?

Answer

Create two users/tenants, have user A create objects, then call every object endpoint as user B with A's IDs and assert 404/403 — ideally generated from the OpenAPI spec in CI.

Open in the app to mark lessons complete, take notes and track your progress.