scanrub
Time-of-check Time-of-use (TOCTOU) Race Conditionlow prioritypartial coverage

Time-of-check Time-of-use (TOCTOU) Race Condition

3 min read 14 reports analyzed ScanRub Research
Share

Summary

TOCTOU (CWE-367) is the specific check-then-act shape of a race condition: the application first checks a condition - "does this coupon still have uses left?", "is there still stock for this item?", "has this invite already been redeemed?" - and only afterward acts on the result of that check. The bug is the gap between the two steps. If a second request runs its own check during that gap, before the first request has written back the updated state, both requests see the same "still valid" answer and both proceed, even though only one should have been allowed to. It's a narrower, more specific pattern than the general concurrent-shared-resource category: every TOCTOU bug is a race condition, but not every race condition follows the literal check-then-act structure (some involve two operations racing to write the same field with no read/check step at all).

◈ flow diagram
Parallel Req…Shared Resou…Check Condit…Time WindowExploit StateInconsistent…
◈ chart
Critical
1
High
4
Medium
6
Low
4

Top Affected Components / Targets

  • Inventory/stock-check-then-purchase flows
  • Balance-check-then-withdraw or transfer flows
  • Validity-check-then-redeem flows for coupons, invites, and referral codes
  • Any endpoint whose logic reads as "if [condition], then [state-changing action]" against a value another concurrent request can also be reading

Common Attack Vectors

  • Fire concurrent requests at an endpoint whose business logic requires a pre-condition (stock > 0, balance sufficient, code unused) to hold before completing the action
  • Look for endpoints where the "check" and the "use" are separated by any amount of processing time - network I/O to a database, a call to another internal service - since that gap is exactly the window a race needs
  • Prefer resources with a hard, human-visible ceiling (a single coupon, one free trial, a fixed stock count) where "more successes than the ceiling allows" is unambiguous proof, over soft limits that are harder to verify externally

Common Payloads

  • No injected payload - identical to the general race-condition case, the "payload" is concurrent timing, not request content
  • A burst of concurrent requests against the same check-then-act endpoint, sized to reliably land at least two requests inside the check-to-write gap

Detection Strategy

Same operational approach as the general race-condition module - a concurrent burst with no prior state-consuming baseline call, reading the distribution of outcomes rather than comparing to a sequential baseline - but specifically targeted at endpoints whose business logic implies a check-then-act structure (redemption, claiming, stock-limited purchase) rather than at arbitrary state-changing endpoints. A ceiling that's exceeded (more successful redemptions than the resource's max-use count) is the clearest possible confirmation, since it rules out coincidence.

Tip: Testing tools that run these checks in parallel across every discovered endpoint can cut the time required substantially compared to fully manual testing, as long as they confirm findings with more than one signal to keep the false-positive rate down.

False-Positive Notes

A resource with no enforced ceiling at all (an endpoint that's supposed to be repeatable) will show all-success under a burst and isn't a TOCTOU bug - the finding requires evidence that a limit exists (documented, or inferred from a single successful "first" outcome under sequential testing) and was then exceeded under concurrency.

How to Test

Manual Testing Methodology

Here is a systematic approach to identifying Time-of-check Time-of-use (TOCTOU) Race Condition vulnerabilities in a target application.

Step 1: Reconnaissance and Surface Mapping

Before testing, map all input vectors that could be affected. Identify parameters, headers, cookies, and request bodies that interact with the vulnerable component. A proxy such as Burp Suite or OWASP ZAP, paired with normal browsing of the target, is usually enough to build this list.

Step 2: Baseline Request

Send a legitimate request and record the normal response: status code, content length, response time, and any identifying tokens. This baseline matters because it's what you'll compare later responses against once payloads are involved.

Step 3: Payload Injection

Inject test payloads into each identified input vector one at a time. Start with benign detection payloads before escalating to anything that could actually trigger the vulnerability. For Time-of-check Time-of-use (TOCTOU) Race Condition specifically, fire the target request (coupon redemption, balance withdrawal, unique-resource creation) many times concurrently and near-simultaneously, using a tool designed for precise request timing rather than a simple loop, since network jitter from sequential requests won't reliably open the race window.

Step 4: Response Analysis

Compare the response against your baseline, looking specifically for whether the action that should only succeed once succeeded multiple times — a balance that went negative, a coupon redeemed more times than its limit, or duplicate unique records created from concurrent requests.

Step 5: Confirmation

Once a potential vulnerability is detected, confirm it with at least a few independent test cases to rule out coincidence. Document the exact request and response as proof. For Time-of-check Time-of-use (TOCTOU) Race Condition, a confirmed finding typically means showing that attacker-controlled input changes the application's behavior in a way that matters for security, not just that a payload was reflected somewhere harmless.

Real-World Impact

Real-World Impact

Race conditions and time-of-check-to-time-of-use flaws exploit the gap between when an application checks a condition and when it acts on it. In that window, an attacker who can fire multiple concurrent requests can get an action approved multiple times that should only have been possible once — redeeming a coupon repeatedly, withdrawing more balance than exists, or registering the same unique resource twice.

These bugs are notoriously undercounted in manual testing because they're invisible to sequential, one-request-at-a-time testing; the vulnerable window is often only milliseconds wide and only opens up under genuine concurrency.

The financial and business-logic impact tends to be direct and quantifiable — free money, bypassed limits, or duplicated unique state — which is part of why race-condition findings are increasingly well-rewarded in bug bounty programs once demonstrated convincingly.

Prevention & Remediation

Prevention and Secure Coding

Preventing Time-of-check Time-of-use (TOCTOU) Race Condition takes a defense-in-depth approach — no single control below is sufficient alone, but together they close off both the primary path and the most common bypasses.

Atomic operations at the data layer. Use database-level atomic operations — row-level locking, compare-and-swap, unique constraints — for any check-then-act sequence involving shared state, rather than checking in application code and acting in a separate step.

Eliminate the check-then-act pattern where possible. Where the data store can enforce the invariant directly (a unique constraint preventing a duplicate row, a conditional update that only succeeds if a balance is still sufficient), rely on that instead of an application-level check.

Idempotency keys for non-repeatable operations. Require a client-supplied idempotency key for operations like payments or coupon redemption, and reject a repeat of the same key regardless of timing.

Test under real concurrency, not just sequentially. Include concurrent-request test cases (fired via a tool built for precise request timing, not just a for-loop) in the test suite for any endpoint that touches shared, limited, or unique state.

Frequently Asked Questions

What is Time-of-check Time-of-use (TOCTOU) Race Condition?
TOCTOU (CWE-367) is the specific check-then-act shape of a race condition: the application first checks a condition - "does this coupon still have uses left?", "is there still stock for this item?", "has this invite already been redeemed?" - and only afterward acts on the result of that check.
How common is Time-of-check Time-of-use (TOCTOU) Race Condition in bug bounty reports?
Scanrub's research corpus for this playbook is built from 14 disclosed HackerOne reports in this category, synthesized for detection and prevention guidance rather than reproduced verbatim.
How do I test for Time-of-check Time-of-use (TOCTOU) Race Condition?
Map every input vector, record a baseline response, then inject targeted test payloads one field at a time and compare the response for timing, length, error, or reflection differences from that baseline. The "How to Test" section above walks through the full methodology for this specific vulnerability class.
What is the single most effective fix for Time-of-check Time-of-use (TOCTOU) Race Condition?
Enforce check-then-act invariants atomically at the data layer (row locking, compare-and-swap, unique constraints) rather than as a separate check followed by a separate action in application code.
Weekly security research

New vulnerability playbooks, tool updates, and bug bounty insights - delivered to your inbox. No spam.

Unsubscribe anytime. We respect your inbox.
Press ⌘K to search×