Platform

Platform overview How it works Authorization testing Evidence & reports Private scanning Integrations

Solutions

Security agencies Product teams Regulated industries Partner programme

Learn

Blog Knowledge hub Compare

Resources

Pricing Documentation FAQ Security & data What we haven’t proved

Company

About Contact Careers Sign in to the platform Start a $199 pilot

Home / Knowledge hub / Race condition

Knowledge hub

Race condition

Two near-simultaneous actions producing a result neither should allow.

What it means

A race condition happens when two operations overlap and the result depends on which one arrives first. Whoever wrote the code assumed requests arrive one at a time. In production they do not.

The classic pattern checks something and then acts on it. The application confirms the balance is sufficient, then deducts it. A second request landing in the gap sees the same balance the first one saw. Both checks pass, both deductions happen, and MITRE describes exactly this case in CWE-362.

Why it matters

The damage is usually financial and repeatable. A voucher redeemed fifty times, a refund issued twice, a withdrawal beyond the balance, a single-use invitation accepted by a dozen accounts, a booking system overselling the last seat.

What makes it awkward is that nothing broke. There is no error and no alert, and the log shows a sequence of requests that each look entirely legitimate. Reconciliation the following month is often how anyone notices, if anyone does.

How it shows up

It is hard to see by reading code, because the flaw lives in the timing rather than in any single line. It is easy to trigger on purpose by firing the same request many times at once, which is how PortSwigger's limit overrun examples work.

Look at anything involving money or stock, voucher redemption, one-time links, registration on a field that must be unique, approval steps, and anywhere a check is followed by a write. The fixes belong at the database: a lock, a transaction with the right isolation, or a unique constraint that makes the second attempt impossible rather than merely unlikely.

Questions people ask

Race condition, answered

How is this different from an ordinary bug?

An ordinary bug reproduces when you repeat the steps. A race condition depends on two things overlapping, so it passes every test that runs them in order.

That is why it survives code review and reaches production intact.

Can an attacker really time it that precisely?

They do not have to be precise. Send twenty copies of the same request in parallel and some of them will overlap.

PortSwigger documents the technique in detail, and it takes an ordinary tool and a few minutes.

Will an idempotency key fix it?

Only if something enforces uniqueness atomically. A key checked with a read and then a write has exactly the same gap you were trying to close.

Put a unique constraint on the key, or take a row lock, so the second request loses rather than duplicating the first.

Does rate limiting prevent race conditions?

No. Rate limiting caps requests over a period. A race needs two requests, and two is under every limit worth having.

It is a useful control for other reasons and it does not touch this one.

Should the fix go in the application or the database?

The database, in almost every case. Application-level locks fail as soon as you run a second instance, and most production systems do.

A transaction with the right isolation, a row lock or a unique constraint holds no matter how many copies of your service are running.

What if two requests arrive together?

Timing flaws live in business logic, and our business-logic module ships on 4 January 2027. Until then we cover the other nine classes with evidence on each finding. Ask what is in scope.

Or start with a $199 pilot on one application: thirty days, success criteria agreed before day one, credited against the annual if you convert.