Race Condition Bug Bounty: Coupons, Wallets, and Limit Bypasses
Limit checks that read-then-write without a lock lose to parallelism. Redeem a single-use coupon twenty times at once; maybe five stick. Withdraw the same wallet balance twice; maybe both debits succeed. That is a race — TOCTOU in business logic.
PortSwigger’s race research and Turbo Intruder-style parallel sends made this mainstream for hunters. You still need the right endpoint.
Features that race well
- Coupon / promo redeem (once per user or globally once)
- Referral bonuses and “first deposit” grants
- Inventory: last seat, limited drops
- Wallet transfer and withdrawal
- Invite codes and seat licenses
- Like/vote counters that unlock rewards
Anything with “remaining uses = 1” in the product copy is a candidate.
How I test
- Establish the slow path: one redeem returns success, second returns “already used.”
- Send a synchronized burst of identical redeem requests (Turbo Intruder, custom async scripts, or last-byte sync techniques from recent research).
- Count successes against the database-visible effect (balance, order line, redemption table) — not just HTTP 200s.
- Repeat a few times; races are probabilistic.
Stay inside rate guidelines. Ten to fifty parallel requests usually prove the class without looking like a DoS.
Evidence that survives triage
Video or request table showing parallel sends, multiple success bodies, and the resulting state (two discounts on one cart, balance above physics). Explain the missing transaction/lock in plain language.
Defenses worth naming
Database unique constraints on redemption keys. Atomic UPDATE ... WHERE uses_left > 0. Idempotency keys. Row locks or serializable transactions around wallet ledgers.
Honest limitations
Some “races” are eventually consistent UI glitches that reconcile. Wait and re-check. If the ledger self-corrects to one redeem, impact may drop to none — say so.
I like coupon and wallet races because impact is obvious in currency. Find the single-use gate, then knock on it together — not harder, just simultaneously.