Skip to content
Security
Skill

/hunt-brute-force

Hunt Missing/Weak Rate Limiting — login brute force, OTP/2FA brute force (10^6 keyspace), password-reset-token brute, credential stuffing, username/email enumeration via error-string / status-code / timing differences, weak password policy, missing CAPTCHA (CAPTCHA token replay

From plugin
claude-bughunter
3.3k82 skills15 commands
Install
$ npx -y skills add elementalsouls/Claude-BugHunter --skill hunt-brute-force --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/hunt-brute-force

Context preview

The summary Claude sees to decide when to auto-load this skill.

Hunt Missing/Weak Rate Limiting — login brute force, OTP/2FA brute force (10^6 keyspace), password-reset-token brute, credential stuffing, username/email enumeration via error-string / status-code / timing differences, weak password policy, missing CAPTCHA (CAPTCHA token replay

SKILL.md

hunt-brute-force.SKILL.md
name: hunt-brute-force
description: "Hunt Missing/Weak Rate Limiting — login brute force, OTP/2FA brute force (10^6 keyspace), password-reset-token brute, credential stuffing, username/email enumeration via error-string / status-code / timing differences, weak password policy, missing CAPTCHA (CAPTCHA token replay / single-use / concurrency-window bypass specifics → hunt-captcha-bypass), IP-based rate-limit bypass via X-Forwarded-For and friends, ReDoS. Distinguishes hard lockout vs soft IP-throttle vs CAPTCHA-injection vs silent shadow-throttling (avoids false-negative 'no rate limit' conclusions). Medium to Critical depending on what the brute reaches (OTP→ATO = Critical)."
sources: public_research
report_count: 0

HUNT-BRUTE-FORCE — Rate Limiting / Brute Force / Enumeration

> Grounding note: this skill is built from published technique classes, not from a > curated set of named HackerOne reports. `report_count` is intentionally `0` — do > not cite an exact payout or report ID you cannot verify. Where a public case is > well-documented (e.g. Laxman Muthiyah's Instagram password-reset OTP race/rotation > research, 2019–2021), it is named below as a *technique reference*, not a payout claim.

Crown Jewel Targets

OTP brute force (6-digit = 1,000,000 combinations) with no effective rate limit = Critical ATO bypass.

**Highest-value chains:**

  • **OTP / 2FA brute → MFA bypass → ATO** — no effective rate limit on `/verify-otp`, full 000000–999999 keyspace reachable
  • **Password-reset token brute** — short/predictable/non-expiring tokens + no rate limit → ATO (the Instagram 2019 case combined a 6-digit reset code, no rate limit per request-source, and IP rotation to make 10^6 tractable)
  • **Username/email enumeration → targeted credential stuffing** — valid/invalid distinguishable by response string, status code, or timing, then sprayed with breach corpora
  • **Coupon / gift-card / referral code brute** — no rate limit on code validation → financial impact
  • **ReDoS** — attacker-controlled input hits a catastrophic-backtracking regex → CPU exhaustion → DoS

---

Autonomous Testing Priority

**Work within your turn budget — prioritize signal over volume.**

You cannot brute-force millions of combinations in automated testing. Focus on two things: (1) credential spraying with the most likely candidates, and (2) detecting whether rate limiting exists at all.

**Strategy:** 1. Identify the login endpoint and the expected parameter names (username/email, password). 2. Try weak/default credentials likely for the target context — default admin credentials for the app's stack, simple passwords for test environments, credentials visible elsewhere on the app (e.g. usernames exposed in profiles, default passwords in documentation). 3. After 3-5 failed attempts, check for rate-limit signals (429 status, "too many attempts" message, CAPTCHA appearance, account lockout message). Absence of these = rate limiting is missing = vulnerability. 4. Use form-encoding for traditional login forms, JSON for REST API login endpoints.

**What to look for as success:**

  • Session token or JWT in the response body or Set-Cookie header
  • Redirect to authenticated dashboard
  • Response body that differs from the failed-login baseline

**Username enumeration (separate finding):** Try a known-valid username vs a random one. If the error message differs ("Wrong password" vs "User not found") or response time differs → user enumeration vulnerability, even without a successful login.

---

CRITICAL: Four rate-limit states — do not collapse them

A `200`/`401` with no `429` does **not** mean "no rate limiting". A rate-limiting skill that only checks for `429`/lockout produces false negatives. Classify the defense BEFORE concluding, by sending a burst of ~50 requests and watching the *full* response (status, body, headers, latency, and downstream success):

| State | Signal | Brute still feasible? | |-------|--------|-----------------------| | **Hard account lockout** | account disabled after N fails; later *correct* creds also fail | No (but lockout itself can be a DoS finding) | | **Soft IP throttle** | `429` / increasing latency keyed on source IP only | Yes — bypass via header/IP rotation (Phase 4) | | **CAPTCHA injection** | `200` but body switches to a CAPTCHA challenge after N | Maybe — check if the verify endpoint enforces it server-side or if the API path skips it | | **Silent shadow-throttle** | `200`/`401` returned for every request, but submissions are *dropped* — the genuinely-correct OTP/password stops being accepted, or responses become canned | **This is the trap.** A naive loop sees "all 200, no 429" and reports "no rate limit" — false. |

**Shadow-throttle detector** — inject a known-good value at a known position and confirm it still works under load:

# Seed: position 500 in the brute set is the REAL OTP for your own test account.
# If the loop reaches 500 and the correct code no longer authenticates,
# the endpoint is silently throttling/dropping — NOT unprotected.
KNOWN_GOOD="123456"   # the actual current OTP for YOUR test account
for n in $(seq 0 600); do
  CODE=$([ "$n" = "500" ] && echo "$KNOWN_GOOD" || printf "%06d" "$n")
  CODE_RESP=$(curl -s -o /tmp/bf_body -w "%{http_code} %{time_total}" \
    -X POST "https://$TARGET/api/verify-otp" \
    -H "Content-Type: application/json" -H "Cookie: $SESSION_COOKIE" \
    -d "{\"otp\":\"$CODE\"}")
  echo "$n $CODE $CODE_RESP $(wc -c </tmp/bf_body)"
done
# Three columns to watch: status, time_total, body size.
# Rising time_total or a body-size change with status unchanged = shadow throttle.

---

Step-by-Step Hunting Methodology

Phase 1 — Login Rate Limit Test (classify, don't just count 429s)

# Send a burst and log status + latency + body length for EACH attempt.
for i in $(seq 1 50); do
  read CODE TIME < <(curl -s -o /tmp/bf_l -w "%{http_code} %{time_total}\n" \
    -X POST "https://$TARGET/api/login" \
    -H "Conte
Read more
Ships withclaude-bughunter

A self-contained Claude skill bundle for bug hunting and external red-team work · 82 skills · 15 slash commands · 681 disclosed-report patterns across 24 core vulnerability classes · enterprise identity + infrastructure attack matrices · engagement-folder

Get the whole plugin

Other skills on claude-bughunter.