Last updated: April 26, 2026
Race conditions in web applications were considered theoretical for years. James Kettle’s research in 2023 changed that — single-packet attacks via HTTP/2 made race conditions reliably exploitable. In 2026, race-condition findings on Indian e-commerce, fintech, and marketplace audits are common: coupon codes redeemed multiple times, OTP brute-force despite “rate limiting,” voucher stacking, account creation deduplication bypasses. This article covers modern race-condition exploitation, the Turbo Intruder workflow, detection, and the application-side fix.
The mental model
A race condition is a Time-of-check-to-time-of-use (TOCTOU) bug — the application checks a condition, then acts on it, with a window between where the state can change. Common patterns:
- Check if a coupon is unused → mark used → apply discount. Multiple parallel requests pass the check before any reaches the mark step.
- Check if a user has 1 vote remaining → cast vote → decrement counter. Parallel votes all see counter=1; all decrement; counter goes negative.
- Check OTP correctness → mark OTP consumed. Parallel attempts can re-test the same OTP.
- Check if username is available → create account. Parallel signups create duplicate users.
The 2023 breakthrough — single-packet attack
Race conditions traditionally required tight timing — fire many requests within milliseconds. Even then, network jitter and TCP round-trips spread arrival across a window large enough that the race window passed before all requests arrived.
HTTP/2 changed this. A single TCP packet can contain multiple HTTP/2 streams (requests). The server receives them all simultaneously and dispatches in parallel. The variability is reduced from milliseconds to microseconds.
Turbo Intruder (Burp extension) implements this attack via the engine=Engine.BURP2 option with single-packet timing.
Practical exploitation with Turbo Intruder
Turbo Intruder is a Burp extension that allows Python-scripted high-throughput requests with precise timing.
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=1,
engine=Engine.BURP2)
for i in range(20):
engine.queue(target.req, gate='race')
engine.openGate('race')
def handleResponse(req, interesting):
table.add(req)
This sends 20 identical requests at the gate, then opens the gate — all 20 hit the server in microseconds. If a race condition exists, multiple succeed where only one should.
Real-world findings (anonymised)
Coupon multi-redemption
An Indian e-commerce platform had ₹500 first-time-user coupons. The check was “has this user used this coupon?” before applying. With 50 parallel requests via Turbo Intruder, we redeemed the same coupon 12 times, getting ₹6,000 off a single order. Engineering had implemented rate limiting at the API gateway (1 request per second per user), but the gateway counted by HTTP request — single-packet attack arrived as one batch.
OTP brute-force despite “lockout”
A fintech app’s OTP verification: “after 5 wrong attempts, lock account for 15 minutes.” Each attempt was checked against the stored OTP; failed attempts incremented a counter. With single-packet attack of 100 OTPs in parallel, most read the counter as below 5 before any wrote-back occurred. We bypassed lockout entirely.
Voucher stacking
Marketplace allowed one voucher per cart. Single-packet attack with two different voucher codes resulted in both being applied — each “checked the cart for existing voucher,” both saw none.
How to test systematically
- Identify candidate endpoints. Anywhere money, votes, account creation, redemption, or one-time tokens are involved.
- Capture a successful request. Get the working state (logged in, valid input).
- Send to Turbo Intruder. Configure single-packet attack with 20-50 parallel requests.
- Analyse results. If response codes vary, or you observe anomalous state (multiple coupons applied, OTP locked-out + accepted), you have a race.
- Verify business impact. Refund the test charges; document for the report.
Detection — what works
- Application-side anomaly detection — N requests for the same resource within microseconds is suspicious. SIEM rule.
- Database-side — look for transactions with unexpected duplicate insertions, counters going negative, votes exceeding population.
- WAF / API gateway — emerging support for HTTP/2 stream rate limiting, but most products are still per-request not per-stream.
The actual fix
Race conditions are state-management bugs. Fixes are at the database level:
- SELECT … FOR UPDATE — pessimistic locking. Reads the row with a write lock; subsequent reads block. Effective; can hurt throughput.
- Optimistic concurrency control — version column on the row; UPDATE WHERE version = X; if affected rows = 0, retry. Good for high-throughput.
- Atomic operations —
UPDATE coupons SET uses = uses + 1 WHERE id = X AND uses < max_uses. The check and update are atomic; race-free. - Distributed locks (Redis SET NX EX) — for cross-service operations.
- Idempotency keys — client provides a unique key per logical operation; server deduplicates.
Application-layer “rate limiting” does not solve race conditions reliably. The fix is at the data layer.
How to find your next race
- Every endpoint that says “you can only do this once” or “you have N attempts” is a candidate.
- Account creation, password reset, OTP verification, coupon redemption, voting, KYC verification, balance transfers.
- Particularly: any flow where the application reads-checks-writes without explicit transactional locking.
Compliance angle
- OWASP API Top 10 API4:2023 — Unrestricted Resource Consumption.
- DPDP §8(5) — race conditions causing financial / data harm fail reasonable security.
- RBI / Payment — race conditions in payment flows are reportable as customer-impacting.
The takeaway
Race conditions in 2026 are no longer theoretical. Single-packet attacks made them reliably exploitable; Turbo Intruder makes them trivially testable. Most production applications have at least one race waiting to be found in money-touching flows. The fix is database-layer, not application-layer. Test your own application this week with Turbo Intruder against your top three “you can only do this once” endpoints. The findings will be financial.
Get a VAPT scoping call
Senior practitioner-led VAPT — not a checklist run by juniors. CVSS-scored findings, free retest, attestation letter. India's SMBs and SaaS teams.