SkillAgentSearch skills...

hunt-race-condition

Hunting skill for race condition vulnerabilities. Built from 12 public bug bounty reports including modern HTTP/2 single-packet attack cases (James Kettle DEF CON 2023 "Smashing the State Machine"; RyotaK / Flatt Security 10,000-request first-sequence-sync expansion 2024).

Install / Use

npx skills add elementalsouls/Claude-BugHunter --skill hunt-race-condition

Installs into whichever agent you are using.

About this skill
📄

SKILL.md

Installable skill definition

Quality Score

96/100

Category

Security

Supported Platforms

Universal

Our assessment of hunt-race-condition

hunt-race-condition scores 96/100 on our quality scale, 146th of 775 Security skills we index (top 19%).

Its SKILL.md is 34 KB long, well organised into 42 sections with 9 code examples: a thorough specification that gives an agent plenty to work with.

With 4,669 GitHub stars, it is one of the more widely adopted skills in the catalogue.

Substance
30/30
Structure
20/20
Description
15/15
Adoption
16/20
Freshness
15/15

Maintenance, license and trust

  • The repository was last updated 2 days ago, so hunt-race-condition is actively maintained.
  • It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
  • Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.

hunt-race-condition compared with similar skills

All 4 of these similar skills score higher than hunt-race-condition; compare them before choosing.

SkillScoreStarsUpdatedFormat
hunt-race-condition (this skill)by elementalsouls964.7k2d agoSKILL.md
algorithmic-artby anthropics100177.9k5d agoSKILL.md
pptxby anthropics100177.9k5d agoSKILL.md
designby nextlevelbuilder100130.2k7d agoSKILL.md
ui-ux-pro-maxby nextlevelbuilder100130.2k7d agoSKILL.md

Frequently asked questions

How do I install hunt-race-condition?
Run npx skills add elementalsouls/Claude-BugHunter --skill hunt-race-condition. The install tabs above show the steps for each supported agent.
Which AI agents does hunt-race-condition work with?
It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
Is hunt-race-condition safe to use?
It is MIT-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is hunt-race-condition still maintained?
The repository was last updated 2 days ago, so hunt-race-condition is actively maintained.

name: hunt-race-condition description: Hunting skill for race condition vulnerabilities. Built from 12 public bug bounty reports including modern HTTP/2 single-packet attack cases (James Kettle DEF CON 2023 "Smashing the State Machine"; RyotaK / Flatt Security 10,000-request first-sequence-sync expansion 2024). Covers coupon double-redemption, gift-card double-spend, MFA-OTP-validate race, account-create race, faucet/crypto token double-mint, email-activation race, vote/upvote inflation, password-reset token race, rate-limit bypass via concurrent requests. Use when hunting race conditions, TOCTOU bugs, MFA-bypass-via-timing. sources: github, hackerone_public, portswigger_research, flatt_security report_count: 10

Firing a race — two primitives (tooling-agnostic)

Winning a race needs requests that arrive in the same narrow window — sequential sends never work. Use a single-packet / synchronized-send tool: Burp Repeater "Send group in parallel" (HTTP/2 single-packet attack), Turbo Intruder (engine=Engine.BURP2, gate sync), or any client that can flush N requests simultaneously. Two shapes:

  • Identical-copies race — fire N IDENTICAL copies of one request at once (limit-overrun: double-spend a coupon/gift-card, exceed a one-per-user quota). Success = ≥2 of the N return 2xx.
  • Different-requests race (partial construction) — fire a LIST of DIFFERENT requests in one synchronized window, repeated over several rounds. For register-then-confirm / TOCTOU races where the object exists in a usable state mid-creation. Example (email-verification bypass — register an arbitrary email, then confirm it through the construction window with a blank token):
    Request A:  POST /register   body: csrf=<csrf>&username=hacker&email=anything@exploit.net&password=pw
    Request B:  GET  /confirm    params: token=   (empty)
    Fire A and B together, repeat ~20 rounds.
    
    Get a fresh CSRF from GET /register first, then fire the batch. After it succeeds, log in as the new account and perform the objective (e.g. a state-changing admin action such as deleting a user). The blank-token confirm wins during the window where the user row exists but its verification token isn't set yet.

Crown Jewel Targets

Race conditions are high-severity findings because they break financial, access control, and integrity assumptions that defenders rarely stress-test. Highest payouts come from:

  • Monetary/credit systems — double-spending gift cards, coupons, referral bonuses, promotional credits, wallet balances
  • Vote/reputation manipulation — upvoting the same content multiple times, gaming leaderboards or trending algorithms
  • Account limits bypass — exceeding free-tier quotas, bypassing "one per user" restrictions on invites, trial activations, or API key generation
  • Privilege escalation — racing role assignment or permission checks during user creation/upgrade flows
  • Deletion bypass — reading or exfiltrating data during a narrow window between "marked for deletion" and "actually deleted"
  • Payment flows — charging a card once but receiving multiple fulfillments

Best-paying asset types: Fintech apps, SaaS platforms with credit/subscription models, social platforms with reputation systems, e-commerce checkout flows, OAuth/SSO token endpoints.


Attack Surface Signals

URL Patterns

/vote, /upvote, /like, /favorite
/redeem, /apply-coupon, /use-code, /claim
/purchase, /checkout, /confirm-order, /pay
/transfer, /withdraw, /send-money
/invite, /referral, /accept-invite
/upgrade, /activate, /trial
/delete, /deactivate, /cancel
/follow, /subscribe

Response Headers That Signal Race-Prone Backends

X-RateLimit-*        # rate limiting exists, but may not be atomic
X-Request-Id         # each request independently tracked
No Cache-Control     # stateful ops not idempotent

JavaScript Patterns to Grep

// Single-use action buttons with client-side disable
button.disabled = true
$('#btn').prop('disabled', true)
// Optimistic UI updates (state set before server confirms)
setState({ used: true })
// Sequential async calls without locking
await useVoucher(); await deductBalance();

Tech Stack Signals

  • Ruby on Rails without with_lock / lock! — ActiveRecord doesn't lock by default
  • Node.js with async/await chains — non-atomic DB reads then writes
  • PHP without SELECT ... FOR UPDATE — common in legacy codebases
  • Microservices — inter-service calls introduce natural TOCTOU windows
  • Redis counters without Lua scripts or INCR atomicity checks
  • Message queues — idempotency keys often missing

Step-by-Step Hunting Methodology

  1. Enumerate one-time or limited-use actions — Map every endpoint that enforces a "once per user", "limited quantity", or "deduct balance" constraint. These are your primary targets.

  2. Understand the state machine — For each target action, identify: (a) what state is read, (b) what state is written, (c) what validation sits between read and write. The gap between read and write is your window.

  3. Capture a clean baseline request — Perform the action once legitimately with Burp Suite intercepting. Confirm you get the expected single-use behavior (e.g., coupon marked used, vote counted once).

  4. Set up parallel request tooling — Use one of:

    • Burp Suite Repeater → "Send group in parallel" (Turbo Intruder for HTTP/2 single-packet attacks)
    • Turbo Intruder with engine=Engine.BURP2 for last-byte sync
    • curl with & backgrounding
    • Python threading or asyncio with pre-built connections
  5. Execute the race — Send 10–50 identical requests simultaneously. Key technique: pre-connect and buffer all requests, release the final byte of all simultaneously (single-packet attack when HTTP/2 is available).

  6. Analyze responses — Look for:

    • Multiple 200 OK where only one should succeed
    • Duplicate success messages
    • Database constraint errors (signals the race worked but hit the last-line-of-defense)
    • Inconsistent response times (one fast, rest slow = serialized; all same speed = parallel processing)
  7. Verify the effect — Check the actual state: Was the credit applied twice? Did the vote count increment multiple times? Is the coupon still marked unused despite two successes?

  8. Determine exploitability window — Re-run with decreasing parallelism (5 requests, 3 requests, 2 requests) to understand how tight the window is and reliability of exploitation.

  9. Test across account types — Sometimes the race only works for new accounts, specific subscription tiers, or under specific server load. Test varied conditions.

  10. Document reproducibility — Record exact timing, number of parallel requests needed, and success rate across 5 independent attempts before reporting.


Payload & Detection Patterns

Turbo Intruder — Basic Parallel Race

# turbo_intruder_race.py
def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=1,
                           engine=Engine.BURP2)  # HTTP/2 single-packet
    for i in range(20):
        engine.queue(target.req, gate='race1')
    engine.openGate('race1')

def handleResponse(req, interesting):
    if '200' in req.status:
        table.add(req)

curl — Parallel Requests (bash)

# Fire 15 simultaneous vote/redeem requests
for i in $(seq 1 15); do
  curl -s -o /dev/null -w "%{http_code}\n" \
    -X POST "https://target.com/api/vote" \
    -H "Cookie: session=YOUR_SESSION" \
    -H "Content-Type: application/json" \
    -d '{"report_id": "12345", "vote": "up"}' &
done
wait

Python asyncio Race

import asyncio, aiohttp

async def race_request(session, url, payload, headers):
    async with session.post(url, json=payload, headers=headers) as r:
        return await r.text()

async def main():
    url = "https://target.com/redeem"
    payload = {"code": "GIFT50"}
    headers = {"Cookie": "session=XXXXX"}
    
    async with aiohttp.ClientSession() as session:
        tasks = [race_request(session, url, payload, headers) for _ in range(20)]
        results = await asyncio.gather(*tasks)
    
    for r in results:
        print(r[:100])  # print first 100 chars of each response

asyncio.run(main())

Grep Patterns for Source Code Auditing

# Look for read-then-write without locking
grep -rn "find_by\|where.*first" --include="*.rb" | grep -v "lock"
grep -rn "SELECT.*WHERE" --include="*.php" | grep -v "FOR UPDATE"

# JavaScript async without atomicity
grep -rn "await.*get\|await.*find" --include="*.js" -A2 | grep "await.*update\|await.*save"

# Python Django ORM without select_for_update
grep -rn "\.get(\|\.filter(" --include="*.py" | grep -v "select_for_update"

HTTP/2 Single-Packet Check

# Verify target supports HTTP/2 (prerequisite for single-packet attack)
curl -sI --http2 https://target.com | grep -i "HTTP/2\|h2"

Common Root Causes

  1. Check-Then-Act without atomic operations — Developer reads state (if voucher.used == false), then writes state (voucher.update(used: true)) in two separate database operations. Any thread can read the same "unused" state before either writes.

  2. Missing database-level locking — Using ORM methods like find or filter instead of SELECT ... FOR UPDATE. The fix is one line but developers don't think about concurrency.

  3. Optimistic concurrency without version checking — Systems increment counters or mark records without checking if the record changed since it was read.

  4. Microservice TOCTOU — Service A validates eligibility, Service B executes the action. No shared atomic transaction spans both services.

  5. Client-side "protection" — Developers disable the button in JavaScript after first click, assuming that prevents duplicate submissions. Server-side logic is never hardened.

  6. Counter increments outside transactions — votes_count += 1; save() instead of an atomic SQL UPDATE SET votes = votes + 1 WHERE id = ?.

  7. Async background jobs — Eligibility checked synchronously, fulfillment done asynchronously. A second request passes the check before the first job completes.

  8. Caching without invalidation — Cached "has user voted?" check returns stale false during a cache miss window when the first write hasn't propagated yet.


Bypass Techniques

What Defenders Implement (and How to Bypass)

Defense: Per-user rate limiting

  • Bypass: Rate limits are checked before the action executes. Send requests simultaneously — all pass the rate-limit check before any is counted.

Defense: Idempotency keys / unique request tokens

  • Bypass: If the server generates or reuses the token, try sending parallel requests without the token. Or check if the uniqueness check itself has a race window.

Defense: Database unique constraints

  • Bypass: The constraint catches duplicates after the race. The first two may both succeed before DB enforces. Look for partial fulfillment — sometimes one succeeds and one errors but both are honored.

Defense: Short time windows / expiring tokens

  • Bypass: Pre-stage all requests with valid tokens. Use single-packet HTTP/2 to release all in one TCP frame — server processes them in the same scheduler slot.

Defense: Queue-based serialization

  • Bypass: Multiple queues (or multiple workers consuming the same queue) can pick up duplicate messages. Test by overwhelming the queue during the window.

Defense: Application-layer mutex / locks

  • Bypass: Distributed systems running multiple app servers don't share in-process locks. Send requests to the same endpoint via different CDN nodes or load-balanced servers.

Defense: "Already used" checks in application code

  • Bypass: The check and the update are separate. The check passes for both

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars4.7k
CategorySecurity
Updated2d ago
Forks704

Languages

Python

Trust signals

100/100

From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.

No cautions