Glossary
API Race Condition

API Race Condition

Alex Khazanovich

Send the same "redeem gift card" request 20 times within one millisecond, and a vulnerable API may honor it several times. That is an API race condition: a flaw that only shows up when requests overlap, and one attackers can now trigger on demand.

Key Takeaways

  • An API race condition happens when concurrent requests change shared data between a check and the action based on it.
  • Attackers use it to redeem codes, withdraw funds or bypass limits more than once.
  • Atomic database writes close the gap, idempotency keys stop duplicates and rate limiting barely helps.
  • Testing needs truly parallel requests, such as PortSwigger's single-packet attack.

What Is an API Race Condition?

An API race condition occurs when the result of an API call depends on the timing of other calls touching the same data. MITRE lists the weakness as CWE-362: code that needs exclusive access to a shared resource, with a window in which another operation can change it. In APIs, it is usually a database row such as a balance, coupon or stock count. Each request is valid alone. Running them together causes the damage.

{{cool-component}}

How Race Conditions Are Exploited in Real API Environments

The usual goal is a limit overrun, where something meant to happen once happens several times:

  • In 2014, the Bitcoin exchange Flexcoin lost 896 BTC after an attacker fired thousands of simultaneous transfers before balances updated. It shut down days later.
  • In 2015, researcher Egor Homakov sent two simultaneous $5 transfers between Starbucks gift cards and turned $10 into $20.

Timing used to be the hard part. In 2023, PortSwigger's James Kettle showed a single-packet attack over HTTP/2 that lands 20 to 30 requests within about 1 ms, enough to hit race windows that are often just as short.

The TOCTOU Problem: Why Check-Then-Act Logic Creates Vulnerabilities

Most API race conditions are time-of-check time-of-use (TOCTOU) flaws, listed as CWE-367. The code reads, decides, then writes:

  1. Read the balance: $100.
  2. Check that it covers an $80 withdrawal.
  3. Subtract $80 and save.

If two requests both pass step 2 before either finishes step 3, the account pays out $160. In-memory locks on one server do not help when a load balancer spreads requests across several instances.

How Idempotency Keys and Atomic Operations Prevent Race Conditions

The fix is to make the check and the change one indivisible database step:

  • An atomic update that subtracts the amount only if the balance is still high enough
  • Row locks with SELECT ... FOR UPDATE, so competing transactions wait
  • Unique constraints, such as one redemption per code, enforced by the database
  • Conditional requests with ETag and If-Match, where a stale write gets 412 Precondition Failed

API idempotency handles retries and duplicates: the client sends a unique Idempotency-Key header, and the server returns the stored result for repeats. Stripe keeps keys for at least 24 hours and answers a concurrent duplicate with 409 Conflict. Attackers can send different keys, though, so idempotency complements atomic writes.

{{cool-component}}

How to Test APIs for Race Condition Vulnerabilities

Race conditions belong in API security testing because sequential tests never trigger them:

  • List endpoints that check a limit and then change state.
  • Send 20 to 30 identical requests in parallel with Burp Suite Repeater's "send group in parallel" or Turbo Intruder's single-packet template.
  • Compare the final state, such as a balance, with what should be possible.
  • Repeat runs, since races are probabilistic.

Conclusion

An API race condition turns valid requests into an exploit through timing alone. Make state changes atomic, add idempotency keys for retries and test every check-then-act endpoint with parallel requests.

FAQs

How Does a Race Condition Differ From a Deadlock?

A race condition finishes with the wrong result because operations interleave unexpectedly. A deadlock never finishes: two transactions each hold a lock the other needs, so both wait. PostgreSQL detects deadlocks and aborts one transaction, while races usually go unnoticed until someone checks the numbers.

Are API Race Conditions Considered Security Vulnerabilities or Bugs?

Both. They start as concurrency bugs, but once an attacker can trigger one deliberately for money, credit or access, it is a vulnerability. MITRE lists them as CWE-362 and CWE-367, OWASP's Top 10:2025 maps CWE-362 to Insecure Design, and bug bounty programs pay for them.

Which API Endpoints Are Most Commonly Vulnerable to Race Conditions?

Any endpoint that checks a limit and then changes state: payments and withdrawals, gift card and coupon redemption, referral bonuses, seat or stock reservations, voting and one-time actions such as email verification. Login attempt limits can be bypassed the same way, giving attackers extra password guesses.

Can CDN Edge Rate Limiting Reduce Race Condition Exposure?

Only a little. Edge rate limiting counts requests over windows of a second or more, while a race attack needs about 20 requests in a millisecond. Cloudflare's counters are kept per data center and can lag by seconds. A WAF curbs wider abuse, but the fix belongs in the API.

Does Database-Level Locking Prevent Race Conditions in APIs?

Yes, if the lock covers the whole check-then-act sequence. SELECT ... FOR UPDATE or an atomic conditional update stops two transactions acting on one row at once. PostgreSQL's default Read Committed level does not prevent lost updates by itself, and heavy locking can cause deadlocks.

Published on:
October 26, 2026

Related Glossary

See All Terms
This is some text inside of a div block.