Skip to content
All notes

security · 18 Oct 2026

Race conditions, explained with a ₹500 wallet

How two requests sent at the same instant can spend the same money twice, and the simple fixes developers should use.

A race condition happens when the result of an operation depends on the timing of two or more things that were never meant to overlap. In web apps, the classic case is money.

The setup

A wallet app has ₹500 in your balance. Withdrawing ₹500 runs this logic on the server:

1. read balance            → 500
2. if balance >= amount    → yes
3. send ₹500
4. balance = balance − 500 → 0

Looks safe. But what if two withdraw requests arrive at the same millisecond?

Request A: read balance → 500
Request B: read balance → 500      ← A hasn't written yet
Request A: 500 >= 500 ✔  send ₹500
Request B: 500 >= 500 ✔  send ₹500
Request A: balance = 0
Request B: balance = 0

₹1,000 left a ₹500 wallet. Both requests passed the check because the check and the update weren’t one atomic step. This gap is called a time-of-check to time-of-use (TOCTOU) window.

Why it matters

The same pattern shows up anywhere a limit is checked and then used: coupon codes meant for one use, “one vote per user”, gift card balances, rate limits. It’s part of the OWASP testing guide, and it’s worth testing for in any authorised assessment.

How developers fix it

  • Make it atomic in the database. One statement that checks and updates together: UPDATE wallets SET balance = balance - 500 WHERE id = ? AND balance >= 500 and treat “0 rows updated” as insufficient funds.
  • Lock the row (SELECT … FOR UPDATE) inside a transaction so the second request waits.
  • Idempotency keys so a retried or duplicated request is processed only once.
  • Unique constraints for “only once” actions like redeeming a coupon.

The maths teacher’s footnote

It’s the same lesson I give in class about Time & Work problems: when two workers act on the same job at once, you can’t reason about each one separately. You have to reason about them together.


Only test systems you own or have written permission to test.