Business Logic Vulnerabilities: The Flaws Scanners Can't Find
Business logic vulnerabilities exploit legitimate application workflows rather than broken code, so scanners routinely miss them entirely.
Key takeaways
Business logic vulnerabilities exploit legitimate application workflows rather than broken code, so scanners routinely miss them entirely.
On this page
A business logic vulnerability is a flaw in how an application's workflow is designed, not a mistake in how it's coded. The request sequence is entirely valid, every input passes validation, and no exception is thrown, but the outcome violates a rule the business assumed would always hold, like "a coupon can be redeemed once."
Why this class doesn't behave like the others#
Every other vulnerability class in this series has a signature. SQL injection has a quote character breaking out of a query. XSS has an unescaped tag landing in the DOM. A SAST tool can grep for the pattern; a DAST tool can throw a malicious payload and watch for the response that proves it landed. There's a "wrong" piece of code somewhere, and tooling exists to find it.
Business logic flaws don't have that piece. The code runs exactly as written and designed. There's no injected string, no missing sanitizer, no buffer overrun. The flaw is that the workflow itself has a gap: an assumption developers made about the order operations would happen in, or about what a legitimate user would never think to do. The attacker isn't breaking the application, they're using it correctly, just not in the order or context anyone designed for.
Concrete examples worth knowing#
Double-redeem race conditions. A referral or coupon system checks "has this code been used?", finds no, then credits the account and marks the code used. Fire two requests at the same instant and both can pass the check before either write completes. The account gets credited twice for a code meant to be single-use.
Client-trusted pricing. A checkout flow sends the cart total from the browser and the server accepts it instead of recalculating from the database. Change the price field in the request body and the order goes through at whatever number you sent.
Skippable multi-step workflows. A five-step checkout has a URL per step. If step 4 (payment) doesn't gate access to step 5 (confirmation), guessing the URL for step 5 completes the order without paying.
Reusable password reset tokens. A reset link is issued, used once to set a new password, and stays valid because nothing revokes it after use. Anyone who intercepted the original link, or found it in a log, can reset the password again later.
Negative quantities and prices. A cart that doesn't enforce a minimum on quantity or price fields lets an attacker enter -5 units of a product, which the total calculation may treat as a credit rather than rejecting outright.
Rate limits scoped to the wrong identity. A "forgot password" endpoint is rate-limited per IP address. Rotating through a pool of IPs, cheap with many proxy services, resets the limit every time, turning a control that looks solid on paper into one that stops nobody.
Why can't scanners find business logic flaws?#
SAST tools analyze source code for known-bad patterns: unsafe function calls, tainted data flows, insecure configurations. DAST tools send known-bad payloads and look for known-bad responses: leaked stack traces, reflected scripts, timing that suggests injection. Both depend on a signature to match against.
A business logic flaw produces a request sequence that is, by every technical measure, legitimate: well-formed requests, parameters of the right type and within range, an authenticated session. Nothing about the double-redeem race condition looks different from two customers using coupons at the same moment; the difference is intent and timing, not shape. A scanner has no unwritten business rule to check traffic against, because "a coupon can only be redeemed once" isn't a property of the code, it's a property of the business the code is supposed to enforce. This is exactly why OWASP maintains business logic testing as its own category in the Web Security Testing Guide, separate from injection and authentication testing. It calls for a different method, not a better scanner.
How do you find them?#
Manual testing with an attacker's mindset is the only reliable method, because it asks the questions a scanner can't formalize: What happens if I skip a step? Replay this exact request? Send two of these at once? Go back three steps and come in from a different direction?
Threat modeling the workflow before you build it catches far more than reviewing it after. Once code ships, "how could this be abused" competes with sunk cost and deadline pressure. Sketching the flow first, and asking who can reach each state and what it assumes was true before it, surfaces the gaps while they're cheap to close. A STRIDE-style walkthrough of each multi-step flow (spoofed steps, tampered server-controlled values, repudiated actions, out-of-order data, gates skipped for escalation) turns "trust me, it's fine" into a checklist you can run before shipping. Our threat modeling for engineers guide walks through applying STRIDE to flows like these.
The double-redeem coupon, worked through#
Say a referral program credits $10 to an account when a coupon code is redeemed. The endpoint does this:
- Look up the code, confirm
used = false. - Credit the account balance by $10.
- Set
used = true.
An attacker scripts two near-simultaneous requests with the same code. Both hit step 1 before either reaches step 3, so both read used = false and both proceed to credit the account. The balance ends up $20 richer from a $10 code, and nothing in the logs looks like an attack, just two valid requests arriving close together.
The fix is to stop treating the check and the write as separate steps. Use a database-level atomic operation, an UPDATE ... SET used = true WHERE code = ? AND used = false that returns the rows affected, so the check and the claim happen as one step the database serializes for you. Pair that with an idempotency key tied to the redemption attempt so a retried request can't double-apply, and re-validate server-side at every step rather than trusting a client's account of what already happened. None of it needs new tooling. It needs treating "can this be done twice, out of order, or skipped" as a design question, not a QA afterthought, the same discipline covered in our application security best practices guide.
The call we'd make#
Run your scanners; they're worth it for the classes they're built for. But budget real time for manual walkthroughs of every multi-step flow that touches money, credentials, or state transitions, and do the threat model before the sprint, not after the incident. Business logic flaws don't show up in a scan report. They show up in a support ticket asking why a customer's balance doesn't add up.
Stay Updated
Get the latest tutorials, guides, and insights on AI, DevOps, Cloud, and Infrastructure delivered directly to your inbox.
More from DevOps
Explore more articles in this category
GraphQL Security Best Practices
GraphQL's single flexible endpoint creates attack surfaces REST checklists miss, from introspection exposure to query depth and batching abuse.
Secret Scanning: Stop Secrets From Leaking Into Git
Secrets slip into git through habit and haste, and the only reliable fix is catching them before they're committed, not after.
SAST vs DAST: Which Security Testing Do You Need
A practical comparison of static and dynamic application security testing, what each catches, and how to combine them in your pipeline.
You might have missed
Evergreen posts worth revisiting.