Race Conditions

Exploiting race conditions in concurrent operations

Quick answer

What is Race Conditions?

Race conditions happen when the app doesn't correctly handle concurrent operations. They let you duplicate actions, bypass limits, manipulate intermediate states or exploit the time window between check and use.

Severity

High

Frequency

Less common

Payloads

7

Steps

5

Severity

High

Frequency

Less common

Payloads

7

The TOCTOU pattern (Time-of-Check-Time-of-Use) is the most dangerous: the app checks a condition, but in the time between the check and the action the state changes. This is exploited by sending multiple simultaneous requests to 'win the race'.

Duplicate payments/transfersApplying coupons multiple timesBypassing rate limitingIncrementing likes/votes without limitCreating duplicate resources

Where to look

Discount codes

Applying the same coupon before it's marked as used. The classic race condition target.

Money transfers

Sending two simultaneous transfers with the same balance — possible double-spending.

Likes and votes

Incrementing counters without limit by sending concurrent requests.

Creation with uniqueness

Creating two resources that should be unique (e.g. same username) by sending simultaneous requests.

Payment processing

Adding items to the cart while the payment is processing — pay less than you receive.

Methodology

1

Identify check-then-act operations

Look for code that first checks (enough balance? valid coupon?) and then acts (transfer, apply discount).

2

Prepare requests

Set up 10-50 identical requests in Burp Repeater (Group Send) or Turbo Intruder.

3

Send simultaneously

Fire all requests at once. The goal is for them to reach the server before the first one is processed.

4

Verify results

Was the coupon applied 3 times? Was the transfer duplicated? Were 2 accounts created with the same email?

5

HTTP/2 single-packet attack

HTTP/2 lets you send multiple requests in a single TCP packet — it removes network jitter.

Real-world case

TOCTOU Race Condition with symlinks → server file read → ATO

$5,000+
1

Identify sequential operations

The server runs 3 steps: fsAccess (check it exists) → isBlocked (check it's not blocked) → createReadStream (read the file).

2

Each step resolves symlinks independently

Between step 1 and step 2, the symlink can change its target. 3 resolutions = 3 race opportunities.

3

Manipulate the symlink via Git branches

Create a repo with 2 branches: main (symlink→/etc) and second (symlink→/home). Switch rapidly between branches.

4

Win the race

In ~10-20 iterations the timing aligns: step 1 resolves to /home (allowed), step 3 resolves to /etc (blocked but the check already passed).

5

Escalate to ATO

Read database.sqlite → extract hashes. Read config → extract encryptionKey → derive JWT secret → forge an admin JWT.

Lesson: File operations that resolve symlinks in separate steps are vulnerable to TOCTOU. Git branches let you change the symlink target in a controlled way.

Payloads

Burp Group Send

Repeater → Seleccionar 20 tabs → Click derecho → Send group (parallel)

Python threading

import threading\nfor _ in range(20): threading.Thread(target=send_request).start()

curl parallel

seq 20 | xargs -P 20 -I {} curl -X POST https://target.com/api/apply-coupon -d 'code=SAVE50'

Advanced payloads(account required)

Turbo Intruder — race

def queueRequests(target, wordlists):\n  for i in range(50):\n    engine.queue(target.req, gate='race')\n  engine.openGate('race')

HTTP/2 single-packet

Enviar 50 requests en un solo paquete TCP — requiere HTTP/2 + herramienta compatible

Asyncio race

import asyncio, aiohttp\nasync def race():\n  async with aiohttp.ClientSession() as s:\n    tasks = [s.post(url, data=payload) for _ in range(50)]\n    await asyncio.gather(*tasks)

Double-spending

Enviar 2 transferencias simultáneas: {from: A, to: B, amount: 100} + {from: A, to: C, amount: 100} (saldo = 100)

Exclusive content

Create your free account to access advanced payloads, scripts and bypass techniques

Create free account

Tools

Turbo Intruder (Burp)

Burp extension to send requests at extreme speed with gating.

Burp → Extensions → Turbo Intruder → race.py template

race-the-web

Dedicated tool for race condition testing.

race-the-web config.toml

Tips

Coupons = target #1

Send 10 requests applying the same coupon — if it applies more than once, it's a race condition.

Look for check-then-act

Code that checks first and acts afterwards without an atomic lock is vulnerable.

HTTP/2 removes network jitter

With HTTP/2, all requests travel in the same TCP packet — perfect timing.

hunters training
650

hunters training

labs from real reports
50

labs from real reports

completions
380

completions

in bounties practiced
$200,000

in bounties practiced

40 flags captured this week·Real reports from HackerOne · Bugcrowd · Intigriti·No commitment·Free Academy

Practice Race Conditions with real labs

Apply these techniques in safe environments based on real bug bounty reports.