A race condition in a web application is a vulnerability that appears when the outcome of an operation depends on the order and the exact timing in which several concurrent requests reach the same shared resource. The application assumes a flow runs sequentially and atomically, checking a condition and acting on it, but under real concurrency two or more requests slip into the window that separates the check from the action. The effect is that logic meant to run only once, such as redeeming a coupon or deducting a balance, runs several times over inconsistent state. This article covers the class end to end, from discovery to mitigation.
The essentials: a web race condition is born from a check-then-act pattern (TOCTOU) without atomicity. The attacker fires simultaneous requests to slip into that window and trigger coupon double-spend, balance overrun, quota exhaustion, or rate-limit and MFA bypass. Reliable exploitation is achieved today with the single-packet attack from Burp Repeater or Turbo Intruder. The correct defense is to move the decision into the database with atomic operations, uniqueness constraints, locking, or idempotency keys.
What a race condition is in web applications
Almost every transactional flow follows the same internal shape: read a state, check that it meets a condition, and write a new state. In a world of one request at a time that order is safe. The problem is that a web server handles many requests in parallel, with several workers, threads, or instances touching the same database row. If two requests read the state before either has written it, both believe the condition holds and both execute the action.
The canonical example is the balance. The application reads balance, checks that it is greater than or equal to the amount, and deducts. If two withdrawals of 100 euros arrive at once against a balance of 100, both read 100, both validate, and both deduct, leaving the balance at minus 100. The check was correct in isolation, but not under concurrency.
These vulnerabilities belong to business logic, not to a syntax flaw. There is no badly escaped quote or unsanitized parameter. That is why they escape automated scanners and are usually found only through manual testing that understands the purpose of each endpoint. In the formal taxonomy they map to CWE-362 (concurrent execution using a shared resource with improper synchronization) and its specific case CWE-367, the TOCTOU race condition.
TOCTOU: the window between check and use
TOCTOU, short for time-of-check to time-of-use, describes the root of the problem precisely: there is a time interval between the moment the application checks a condition and the moment it acts based on it. Anything that happens inside that window invalidates the earlier check.
In local systems the concept is classic, for example checking a file's permissions and then opening it, a moment an attacker uses to swap the file for a symlink. On the web the window is the latency between reading and writing the state, often measured in milliseconds or even microseconds. The wider that window, the easier the exploitation. Slow queries, external service calls interleaved between the check and the write, or partial locks widen the window and hand time to the attacker.
The practical consequence is that security cannot rest on the expected order of operations. If the design assumes that the check and the use are inseparable, but the implementation splits them into two separate queries, an exploitable TOCTOU exists. Closing that window, not just narrowing it, is the goal of a correct defense.
Variants of web race conditions
Modern research, in particular PortSwigger's work on state machines, has organized these vulnerabilities into several operational families.
Limit overrun
This is the most frequent and profitable variant. A limit the business wants to apply only once is exceeded by triggering it in parallel: redeeming the same coupon or gift card several times, applying a discount repeatedly, overrunning a balance, voting more than once, inviting more users than allowed, or exceeding a per plan quota. Coupon double-spend is the textbook case: twenty simultaneous redemption requests against a single use coupon, and several of them succeed before the system marks the coupon as used.
Multi-endpoint races
Here it is not identical requests that compete, but requests to different endpoints that operate on the same object. A typical pattern is applying a payment and modifying the cart at the same instant, or confirming an order while changing its amount. The window opens because the object passes through intermediate states that no single endpoint validates in full.
Sub-states and partial construction
Many objects exist for a brief span in a transient, invalid state, for example a half created account or an order not yet confirmed. Hitting that sub-state with a second request can allow operating on an object that should not be available yet, skipping validations that are only applied at the end of the flow.
Real impact
The impact is not theoretical. In e-commerce, limit overrun translates into direct financial loss from coupons and gift cards redeemed multiple times or from negative balances. In banking and fintech, a concurrent overrun can empty the available funds logic. On platforms with subscription plans, quotas per user, per project, or per API call are exceeded, eroding the business model.
There is a security vector on top of the economic one. Anti-brute-force mechanisms are usually implemented as a counter that is read, checked, and incremented, that is, another TOCTOU pattern. By sending many attempts simultaneously, an attacker can try more candidates than the rate limit should allow before the counter updates. The same applies to OTP codes and second factors: a race condition can turn a limit of five attempts into several dozen effective attempts, degrading MFA protection. This overlap with authentication connects directly with what we review in web application penetration testing.
How they are exploited: Burp Repeater and Turbo Intruder
Exploiting a race condition means getting several requests to reach the server so close in time that they all find the same initial state. The great historical obstacle has been network jitter: even if you send the requests at once, they travel through different routes and queues and arrive staggered, closing the window too early.
The classic approach with Burp Suite is to group requests in Repeater and send them in parallel. In Burp you just select several tabs, create a group, and choose the option to send the group in parallel. To tune volume and timing you turn to Turbo Intruder, the high performance scripting extension, with its gate technique: all requests are queued while holding back the last byte and, when they are all ready, the gate is opened with openGate to release them together. Anyone who wants to go deeper into the tool can start with what is Burp Suite in web pentesting.
The single-packet attack
The technique that changed the game is the single-packet attack, presented by James Kettle at Black Hat USA 2023. The idea is to eliminate network jitter entirely by making between twenty and thirty requests reach the server inside a single TCP packet. Over HTTP/2 this is achieved by multiplexing many requests on a single connection and holding back the final frame of each one until the last moment, so the server receives and processes them at practically the same instant. Over HTTP/1.1 there is an equivalent variant with last byte synchronization over concurrent connections.
The result is that the race condition window no longer competes against the variability of the internet, only against the server's internal processing, which makes exploitation reliable even across the public network. Burp Repeater implements this technique directly in its parallel group send option, and Turbo Intruder ships engines ready for the single-packet attack. These same concurrency techniques are also tested against APIs, a terrain we cover in API penetration testing REST and GraphQL.
Detection in an audit
In an audit, the first step is to map the endpoints with check-then-act logic over shared state: coupon redemption, discount application, transfers, balance changes, quota consumption, voting, anti-brute-force counters, and OTP flows. Any endpoint that modifies a limited resource is a candidate.
The test consists of capturing the relevant request, duplicating it into a group, and sending it in parallel with the single-packet attack, then observing whether the effect occurred more times than allowed. A coupon that should be redeemed once and appears redeemed three times, a balance that goes negative, or an attempts counter that does not reflect all the submissions are unmistakable signs. The methodology is captured in the OWASP Web Security Testing Guide, in its race conditions test within the business logic block (WSTG-BUSL-04). This type of finding usually appears alongside other logic and access control flaws that we document in the complete web audit guide.
Defenses
The golden rule is never to trust the execution order and to move the decision to the only point capable of serializing accesses: the database.
The first defense is the atomic operation. Instead of reading, checking in the application, and writing, everything is expressed in a single conditional statement, for example UPDATE accounts SET balance = balance - :amount WHERE id = :id AND balance >= :amount, and the number of affected rows is checked. If it is zero, there were no funds, and no concurrent request can overrun, because the engine serializes the write on the row.
The second is uniqueness constraints at the database level. A unique index on the coupon plus user combination physically prevents a second redemption: the duplicate insert fails even if it arrives in the same microsecond. It is the most robust barrier because it does not depend on application code.
The third is explicit locking. Pessimistic, with SELECT ... FOR UPDATE inside a transaction, locks the row until commit. Optimistic adds a version column and rejects the write if the version changed since the read. Raising the isolation level to serializable is another option, accepting its performance cost.
The fourth is idempotency keys, essential in payments and sensitive mutations. The client sends a unique identifier per operation and the server guarantees that the same key is processed only once, so retries or concurrent submissions with the same key do not duplicate the effect. It is the pattern Stripe popularized and it fits naturally in APIs.
The fifth, for state that does not live in a single database, is the distributed lock, for example with Redis, always understanding its limits and never using it as a substitute for transactional guarantees when those are available. If you need to validate the real exposure of your transactional flows, Secra's web and mobile audit service tests these concurrency vectors under realistic attack conditions.
Frequently asked questions
Is a race condition the same as TOCTOU?
TOCTOU is the most common root cause of web race conditions, the interval between checking a condition and using it, but not every race condition follows exactly that pattern. Some multi-endpoint races exploit transient sub-states without an explicit prior check. In practice, most business logic races are TOCTOU.
Why do automated scanners not find these vulnerabilities?
Because they are not syntax or input sanitization flaws, but business logic flaws under concurrency. A scanner sees a valid request that returns a valid response. Only by sending several simultaneous requests and checking the cumulative effect on a limited resource does the problem show up, and that requires human understanding of the endpoint's purpose.
What is the single-packet attack and why does it matter?
It is a technique that makes between twenty and thirty requests reach the server inside a single TCP packet, eliminating network jitter. It matters because it turns races that were previously only exploitable in a lab, under ideal network conditions, into vulnerabilities that can be exploited reliably across the internet.
Does a rate limit protect against race conditions?
Not necessarily. If the rate limit itself is implemented as read-check-increment without atomicity, it is a TOCTOU target in its own right: several simultaneous requests can pass before the counter updates. A robust rate limit must rely on atomic counters.
What is the best defense at a glance?
Move the check and the action into a single atomic database operation, backed by uniqueness constraints, and add idempotency keys on payments and critical mutations. Purely application level defenses, without a transactional guarantee, tend to leave exploitable windows.
Related resources
- What is SSRF: server-side request forgery
- What is CSRF: cross-site request forgery
- What is CORS and web security
- Web application penetration testing
- What is Burp Suite in web pentesting
- API penetration testing REST and GraphQL
Race condition auditing with Secra
At Secra we treat race conditions as a first order vector in business logic review, not as a lab curiosity. We enumerate the sensitive transactional flows, reproduce the concurrency conditions with the single-packet attack over Burp and Turbo Intruder, and verify whether a single use limit withstands dozens of simultaneous requests. We deliver actionable findings with proof of concept and remediation recommendations focused on atomicity, constraints, and idempotency, prioritized by economic and security impact. If you need to know whether your coupons, balances, quotas, or anti-brute-force counters hold up under a real concurrency attack before an attacker finds out, contact our team through this page.
About the author
Secra Solutions team
Ethical hackers with OSCP, OSEP, OSWE, CRTO, CRTL and CARTE certifications, 7+ years of experience in offensive cybersecurity, and authors of CVE-2025-40652 and CVE-2023-3512.

