loader
critical risk OSI Layer 7 / Authorization current

Broken Access Control and Logic Flaws

The application authenticates the user but fails to enforce what that user is allowed to do, in what order, or how often.

Defender-oriented briefing. This page describes behavior, observable signals, prevention and response. Operational attack instructions are intentionally excluded.

How it works

Authorization is checked inconsistently, derived from client-supplied identifiers, or applied to individual requests without regard to the state, sequence or economic limits of the workflow they belong to.

One failure with three faces

Access control, business logic abuse and race conditions are usually catalogued separately, and they are worth reading together because they share a root cause. In each, the application answers the question it was asked rather than the question that mattered.

Broken access control answers "is this a valid user" instead of "is this user allowed to touch this object". Business logic abuse answers "is this request well formed" instead of "does this request make sense given everything that came before". Race conditions answer "was this permitted when I checked" instead of "is it still permitted now that I am acting".

They also share a detection problem that makes them unusually expensive. None produces an error. Every request is syntactically valid, authenticated, and returns a success response. The application is working exactly as written, which is why these flaws survive scanners, penetration tests scoped to input validation, and years of production traffic.

Object-level authorization

The most common variant remains the simplest. A request references a record by identifier, the application confirms the caller is logged in, and returns the record without confirming the caller owns it. Changing the identifier returns someone else's data.

Sequential identifiers make this trivial to discover, but replacing them with random ones is obfuscation rather than a fix. Identifiers leak — through referrals, exports, support tickets, shared links and the application's own responses. The control has to be the ownership check, not the unguessability of the key.

The structural failure is placing that check in each handler. Authorization written per-endpoint is authorization that will be forgotten at the next endpoint, and the endpoint most likely to be forgotten is the one added under time pressure. Route every data access through a layer that cannot return a record without being told who is asking, and make the unsafe path the one that requires extra effort to write.

Function-level and the second interface

A related pattern hides administrative capability behind the interface rather than behind a check. The button is not rendered, the menu item is absent, and the endpoint answers anyone who calls it.

This surfaces most often where a web UI and an API have diverged. The UI enforces role at render time; the API was written for the UI and inherited the assumption that only the UI would call it. Every mobile client, integration and public API since has been talking to a service whose authorization model lives in a template.

Enumerate the actual surface rather than the documented one. Any route reachable without the UI is a route an attacker will reach without the UI.

Logic that is valid but wrong

Business logic abuse uses the application exactly as designed, in sequences the designer did not consider. A refund processed before a payment settles. A discount applied twice by revisiting a step. A signup bonus claimed repeatedly through accounts that share a payment instrument.

No individual request is malformed. The harm exists only in the aggregate, which is why input validation cannot see it and why these findings almost always come from someone reasoning about the workflow rather than from a tool.

The defence is to write down the invariants — a booking holds exactly one seat, a voucher is redeemed at most once, a balance never goes negative — and enforce them where they cannot be bypassed. In practice that means database constraints and atomic operations, because an invariant enforced only in application code is an invariant that holds until two requests arrive at once.

Concurrency: the check that expired

Race conditions are the timing form of the same problem. Code reads a value, decides an action is permitted, and acts. Between the read and the write, another request does the same. Both were permitted at the moment they checked; both proceed.

The classic result is a single-use item consumed twice — one voucher redeemed by two requests, one balance withdrawn twice, one invitation accepted by several accounts. Attackers exploit this deliberately by firing identical requests simultaneously, which is trivial to do and requires no understanding of the code.

Retry logic makes it worse in a way that is easy to miss. A client that resends on timeout can duplicate an operation that succeeded slowly, turning an ordinary network hiccup into the same outcome an attacker was aiming for.

Fixes are well established and rarely applied consistently: perform the check and the write in one atomic operation, hold the appropriate lock, or let a uniqueness constraint reject the second attempt. Idempotency keys handle the retry case by making a repeated request return the original result rather than performing the action again.

Detection

Because nothing errors, detection depends on looking for outcomes rather than failures.

  • Authorization denials as a monitored metric. A sudden rise means someone is probing; a rate of zero usually means denials are not being recorded, not that none occur.
  • Access patterns per account — one session touching many distinct object identifiers in sequence is enumeration regardless of whether each request succeeded.
  • Invariant violations detected out of band. Periodically assert that balances, inventory counts and redemption tallies still reconcile; a race condition shows up here long before anyone reports it.
  • Duplicate state transitions on the same entity within a short window.
  • Velocity per identity across the dimension that costs money, not merely per IP address.

Testing that finds these

Scanners find injection and miss this category almost entirely, because the requests are valid and the responses are successful. What works is comparative and adversarial.

Automate cross-role testing: capture a request as one user, replay it as another, and assert the response is a denial. Run it in CI against every endpoint so a new route without an ownership check fails the build rather than shipping.

Test concurrency explicitly by firing the same consequential request many times in parallel and asserting the invariant afterwards. Any operation guarding a limited resource deserves this.

And review workflows as sequences rather than endpoints. Ask what happens if a step is skipped, repeated, or performed out of order. Most business logic findings come from that question rather than from any tool.

Also known as

IDOR BOLA business logic abuse race condition concurrency abuse

What defenders may observe

  • Users reach objects belonging to other accounts by changing an identifier
  • Role boundaries differ between the UI and the API
  • Impossible transaction sequences appear in logs
  • One actor repeatedly consumes scarce inventory or a one-time benefit
  • Duplicate state transitions occur within milliseconds of each other

Prevention and mitigation

  • Enforce authorization server-side on every object and every function
  • Deny by default through one centralised policy layer, never per-handler
  • Derive identity from the session, never from a request parameter
  • Model workflow invariants and enforce them in the database, not only in code
  • Use idempotency keys and atomic transactions for anything consequential
  • Run automated cross-role authorization tests in CI

Initial response priorities

  • Contain the vulnerable route or feature.
  • Preserve requests, traces and affected records.
  • Fix the root control failure, test adjacent paths and rotate exposed secrets.

Use your approved incident-response plan and adapt decisions to your environment. This is educational guidance, not a substitute for live incident leadership.

Authoritative references