Eight patterns I look for in API code reviews and Burp traces. Each is paired with the actual fix — not "add authz", but the specific line of code or query change that closes the gap.
CRITICALBOLA01Resource fetched by ID without owner scope
The endpoint queries for the resource by primary key and returns whatever it finds. Any authenticated user can change the ID in the URL and read other users' data. This is OWASP API #1 and accounts for the largest share of bug-bounty payouts.
fix: Scope the query by the authenticated principal: WHERE id = ? AND owner_id = ?. Do not 'fetch then check'.
HIGHBOLA02403 Forbidden returned for cross-owner access
Returning 403 confirms the resource exists; an attacker can enumerate IDs to map other users' inventory. Real outcome: confirmed which order IDs are valid before they steal them.
fix: Return 404 Not Found for both 'does not exist' and 'not yours'. Indistinguishable.
HIGHBOLA03Sequential / guessable resource IDs
Auto-incrementing IDs make BOLA discovery trivial — change ord_1001 to ord_1002 and try again. UUIDs don't fix the underlying authorization bug but raise the cost of mass enumeration significantly.
fix: Use UUIDv4 or another opaque identifier. Combine with the BOLA01 fix; UUIDs alone are not authorization.
HIGHBOLA04Authorization in middleware only, not in the query
Middleware checks 'is the user logged in', then the route fetches by ID. This separation of concerns is correct for AuthN, dangerous for AuthZ — the route still needs to verify ownership.
fix: Push owner-scope into the data layer: a repository method that takes (id, principal) and refuses to return cross-tenant rows.
HIGHBOLA05Mass-assignment on update endpoint
An update endpoint accepts the full order object including ownerId, allowing an attacker to reassign their own order to another user, or to escalate via role= fields.
fix: Whitelist updatable fields. Never trust client-supplied id/owner/role/createdBy on writes.
MEDIUMBOLA06Admin override flag in client request
Endpoint accepts ?admin=true or X-Admin: 1 and skips the owner check. Frequently used by internal tools and never removed before launch.
fix: Trust only server-side claims (session, JWT validated server-side). Strip request-level admin flags at the edge.
MEDIUMBOLA07GraphQL by-ID query without owner scope
GraphQL resolvers commonly expose order(id: ID!) that resolves any record. Same bug as REST; harder to spot because of the schema layer.
fix: Pass the principal into the resolver context. Apply ownership in the data loader, not the resolver. Consider Relay-style global IDs that encode owner.
LOWBOLA08Verbose error messages leak resource shape
Errors like 'order not found in tenant t_acme' confirm tenant existence and naming. Useful for an attacker building a cross-tenant attack chain.
fix: Return generic errors to clients. Log the detail server-side with a correlation ID.