What it is#
Race conditions in web applications typically follow the time-of-check-to-time-of-use pattern. The server reads state — a balance, a coupon count, a single-use token — validates the intended operation against it, and then performs the mutation. Between the check and the mutation, a second request slips through with a stale view of the state and the mutation completes twice. Classic targets include gift-card redemptions, voucher systems, 2FA verification, and follow-request limits.
Why it matters#
Race conditions produce no syntactic error at the HTTP layer. The exploit looks like a valid pair of requests that each return 200 OK, and the damage only appears in the downstream ledger. They are hard to find with fuzzing because the timing window is usually sub-millisecond.
Mitigation direction#
Use atomic database primitives: UPDATE ... WHERE balance >= amount, unique constraints on single-use tokens, optimistic locking with version columns. Move the decision inside the transaction boundary. For distributed systems, a short-lived distributed lock keyed on the resource ID is usually enough.