Race conditions are the one bug class where the proof fits in a chart. This one leaves a perfectly readable trace: thirty-seven 200s for a coupon that allowed one.
The window
The cart code, reconstructed from observed behaviour, does three things in this order: it reads the coupon, it calls the billing service, then it writes the new counter. The network call in the middle opens a window of several tens of milliseconds during which every concurrent request reads the same value.
const coupon = await db.coupon.findOne({ code }); // readif (coupon.uses >= coupon.maxUses) throw new Error('used');const invoice = await billing.apply(cart, coupon); // ← the windowawait db.coupon.update({ code }, { uses: coupon.uses + 1 });Confirmation
Forty requests sent in a single HTTP/2 packet, to remove network jitter between them:
python3 race.py --target https://app.target.tld/api/cart/apply-coupon \ --concurrency 40 --single-packet \ --body '{"code":"WELCOME50"}' \ --cookie "session=████████████████"HTTP/2 200 OK × 37HTTP/2 409 Conflict × 3Thirty-seven 50% discounts applied against a coupon flagged maxUses: 1. The final counter in the database read 1.
Takeaways
- Any
read → decide → writewith a network call inside it is a race condition. The question is not whether the window exists, but whether anyone knows how to aim at it. - The fix is not an application-level lock but a conditional write:
UPDATE … SET uses = uses + 1 WHERE code = ? AND uses < max_uses, then check the affected row count. - The final counter read
1. No business dashboard anywhere would have flagged the abuse.
Disclosure timeline
- Report sent
- Triaged
- Fix deployed conditional decrement in a single SQL statement
- Cleared for publication