What is a race condition?
A lot of program logic quietly assumes that its steps run in order with nothing in between: read a value, decide what to do, then write the result. A race condition exists when that assumption fails and several operations can overlap, so the final result depends on which one finishes first. An attacker who can control the timing can push the program toward an outcome its developer never planned for.
The best-known variety is called TOCTOU, short for time-of-check to time-of-use. The code tests a condition, acts on the answer an instant later, and in between the condition stops being true.
Example: one gift card, forty redemptions
Take a gift-card code worth fifty dollars. For each redemption the service does two things: it reads the balance, and if the balance covers the purchase it writes the reduced amount back. An attacker sends forty redemption requests at the same instant.
- Every request reads the balance while it still says fifty dollars.
- Every request passes its check, since none of the writes has landed yet.
- The service completes forty redemptions on a card that should have paid out once.
No password was cracked and no malicious input was sent; the attacker exploited timing alone. Double-spending in payment systems, duplicate withdrawals and discount codes accepted more often than their limit all come from the same pattern.
File swaps against privileged programs
A second version targets the filesystem. A program running with elevated rights confirms that a file is safe, and only afterward opens it. During that short window the attacker replaces the file with a symbolic link that points to a protected file. The safety check looked at the harmless file, but the open call follows the link to the file the attacker wanted. Swaps like this are a classic way to escalate privileges locally.
Defending against race conditions
The goal is to leave no gap between checking and using, which means making the operation atomic so no other request can slip in between the two steps:
- Do the read and the write inside one database transaction with a suitable isolation level.
- Alternatively, use a conditional update that tests and changes the value in a single indivisible step.
- Lock the resource so only one request can work on it at a time.
- Let the database enforce the business rule instead of trusting checks made in application code.
Each of these is a development practice. A perimeter control cannot close a timing gap inside the application.
Race condition vs. replay attack
Both can involve repeated requests, so a scenario full of requests can point either way. Compare them on three points:
| Point | Race condition | Replay attack |
|---|---|---|
| What is sent | Two or more legitimate requests that overlap in time | One valid message that was captured and is sent again |
| What fails | A check goes stale before the action completes | The resent copy is accepted a second time |
| Scenario clues | Simultaneous requests, double-spending, a value no longer true when it is used | A previously captured message presented again |
Race condition on the CompTIA Security+ exam
Race conditions are listed among vulnerability types under objective 2.4. Scenario wording about concurrent requests, operations happening at the same time, a check that is stale by the time it is used, or double-spending points at it. The distractors are a buffer overflow and a replay attack. The exam-correct fix is atomic operations and locking, built into the code, not a firewall or password control.