Race Conditions

Overview

A race condition appears when correct behavior depends on the order or timing of concurrent operations, but the application does not enforce that order safely. In web applications, this usually means two or more requests reach the same shared state at almost the same time and the application makes decisions using stale or inconsistent data. These notes cover the concurrency model, TOCTOU bugs, practical business-logic cases, and how to think about testing race conditions in real applications.

Programs, Processes, and Threads

A program is static code. A process is that code running. A thread is a lightweight execution unit inside a process.

This matters because many web servers handle multiple requests at once by using multiple workers, threads, or asynchronous execution. Once more than one request can touch the same data at the same time, race-condition risk appears.

Why Web Apps Are Vulnerable

Web applications are full of shared state:

If two requests read that state before either one writes back the new value, both may act as if they were first.

TOCTOU

The most important race-condition pattern is Time of Check to Time of Use, usually shortened to TOCTOU.

The application checks whether an action is allowed, then later performs the action. If another request changes the underlying state in between, the original decision may no longer be valid.

Simple Analogy

Two restaurant hosts both see table 17 as free. Each one promises it to a different caller before the “reserved” marker is actually placed on the table. The check was correct when it happened, but the later use of that information was no longer safe.

That is the same logic bug web applications make with funds, coupons, seats, quotas, and one-time actions.

Banking Example

Suppose an account has $75 and two concurrent requests each attempt to withdraw $50.

That is a classic TOCTOU failure: the validation step and the state update were not atomic.

Coupon Example

Coupon redemption is another common race target. The application may follow a flow like this:

If two requests hit the “apply” action before the coupon is marked used, the discount may be applied more than once.

Common Race Targets in Web Apps

Where The Bug Usually Lives

The vulnerability is rarely “threads are bad” by itself. The real issue is usually one of these:

What To Look For

Testing Approach

The goal is not just “make requests fast.” The goal is to hit the narrow window between check and update.

Why Parallel Requests Matter

Single-request testing may never reveal the bug because each request looks valid in isolation. The issue only appears when two operations overlap in time and both trust stale state.

This is why race-condition testing belongs in business-logic testing, not just low-level concurrency theory.

Client-Server Context

Most web applications use a multi-tier architecture:

Race conditions often happen because the application tier checks something, then the data tier changes in a separate step instead of one protected transaction.

Typical Outcomes

Mitigation

Key Takeaways