Business Logic Vulnerabilities: The Bugs Automated Scanners Still Miss
A request can be perfectly well-formed, correctly authenticated and still wrong. Logic flaws live in the sequence, not the syntax.
Most vulnerability classes have a signature. Injection has a payload that changes how input is parsed. Misconfiguration has a setting with a known-bad value. A scanner can look for both because there is something identifiable in the request or the response.
Business logic flaws have no signature. Every request is well-formed. Every parameter is the right type. The session is valid and the user is authorised for each individual call. The defect is in the relationship between the calls — an order that reached fulfilment without a successful payment, a discount applied twice, a subscription tier that survived a downgrade.
Technically valid, semantically wrong
The defining property of this class is that no single request looks suspicious. Consider a checkout flow with the intended sequence:
cart -> payment authorised -> order created -> fulfilment
Each transition is a legitimate endpoint. Each requires authentication. The flaw appears when the application will accept order created without having recorded a successful payment authorisation — because the state was tracked client-side, because the payment callback is trusted without verification, or because a retry path re-enters the flow at the wrong step.
Common territory for this class:
- Sequencing — steps completed out of order, or skipped entirely
- Pricing and totals — recalculation on the client, or trusted from the request
- Discounts and entitlements — reuse, stacking, or persistence past expiry
- Subscription state — access retained after cancellation, downgrade or non-payment
- Approval workflows — self-approval, or transitions that skip a required reviewer
- Quantity and limits — negative values, or limits enforced per request rather than per account
- Refunds and reversals — value returned more than once, or returned without the goods
Modelling the application as a state machine
The technique that makes this class systematic is to stop thinking in endpoints and start thinking in states. For each business object, write down the states it can occupy and the transitions the business intends between them.
DRAFT -> SUBMITTED -> APPROVED -> FULFILLED
\
-> REJECTEDThen work through the matrix the model implies. For every pair of states, the question is: can this transition be reached, by whom, and was it meant to exist? Three categories are worth targeting first:
- Transitions that skip a state. DRAFT straight to FULFILLED. These are usually the highest impact because they bypass the control the intermediate state existed to enforce.
- Transitions that reverse. FULFILLED back to DRAFT, then forward again — often the path to duplicating value or re-triggering a one-time action.
- Transitions performed by the wrong actor. The transition is valid; the actor is not. Self-approval is the canonical example.
Why automated tools miss these
This is not a criticism of scanners. It is a description of what they are built to reason about.
| A scanner understands | A logic flaw requires |
|---|---|
| HTTP structure and parameters | Knowledge of what the application is for |
| Known vulnerability signatures | Knowledge of intended business rules |
| Response codes and content diffs | Knowledge of which state should be reachable |
| A single request in isolation | The relationship between several requests |
| One authenticated session | Multiple roles and their intended separation |
Nothing in a request that skips the payment step is anomalous at the protocol level. The tool would need to know that payment was supposed to precede fulfilment — which is domain knowledge, not protocol knowledge. That is why this class remains a human specialism, and why it is well represented in bug bounty findings on mature targets that have already been scanned thoroughly.
Practical testing approach
- Read the product before the traffic. Documentation, pricing pages and onboarding describe the rules the application is supposed to enforce.
- Complete each workflow once, legitimately, and record the full sequence.
- Draw the state machine for each business object from that recording.
- Provision multiple accounts, roles and tenants — logic flaws frequently need two actors to demonstrate.
- Attack the sequence, not the request: replay steps, reorder them, resume abandoned flows, run two flows concurrently against one object.
- Check enforcement on the server for every value the client can influence: price, quantity, tier, identifiers, state fields.
- Verify that limits are enforced against the right scope — per account and per period, not per request.
- Confirm the finding by observing the resulting state, not just the response code.
Defensive controls
- Model workflows explicitly as state machines in code, with transitions validated server-side
- Reject any transition not declared valid from the current state — fail closed
- Recompute all values with financial or entitlement meaning on the server
- Enforce idempotency on operations that create or move value
- Separate the actor who requests from the actor who approves
- Log state transitions with actor, from-state and to-state so anomalies are reviewable
- Cover intended transitions with tests, and add a test for each invalid transition found
Conclusion
Business logic testing rewards understanding over tooling. The finding is rarely in a payload; it is in the gap between what the developers implemented and what the business assumed. Closing that gap is an engineering exercise — make the intended process explicit in code, and make everything else unreachable by construction.
References
- OWASP Web Security Testing Guide — business logic testing
- OWASP Abuse Case Cheat Sheet
- OWASP Top 10 — Insecure Design
Bring this to your own environment.
If any of the above describes a system you are responsible for, the fastest next step is a conversation about scope.
