Bot and Fraud Defense skill for Claude Code

Stop credential stuffing without taxing real users. Claude names the attack and what it costs, baselines login, signup, SMS and checkout metrics, then layers controls: velocity limits keyed on account, IP, ASN and device, Pwned Passwords checks, server-verified Turnstile challenges and step-up MFA for risky traffic only. Rules launch in shadow mode with friction metrics, so you block bots without silently losing real customers.

  • namebot-fraud-defense
  • size185 lines · ≈2,600 tokens
  • files1
  • licenseMIT
  • updated

What Claude sees before loading it

This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.

description: Defends signup, login, checkout, and content endpoints against automated abuse - credential stuffing, fake account creation, card testing, SMS pumping, promo abuse, and aggressive scraping - with layered signals (velocity per account, IP, ASN, device), breached-password checks, invisible challenges such as Cloudflare Turnstile, progressive friction, and metrics to tune false positives. Use when login failures spike, fake signups or disposable emails flood in, SMS or card-testing bills jump, bots scrape pricing or content, or when choosing a CAPTCHA.

Try asking

  • Our failed logins went from 2k to 400k a day. Help me stop this credential stuffing attack
  • We are paying for thousands of OTP texts to numbers that never verify. How do we stop SMS pumping?
  • Should we add a CAPTCHA to signup, and which one? Fake accounts are flooding our free tier

Use it when

  • Failed login ratio or signups spike without a marketing reason
  • SMS, card authorization, or chargeback costs jump suddenly
  • Disposable emails or duplicate accounts abuse a free trial or promo
  • Bots scrape pricing or listings faster than your infra can serve

Skip it when

  • You only need rate limit algorithms and headers — use rate-limiting instead
  • You are building the login and session system itself — use auth-sessions instead

How to check the result

Run new rules in shadow mode first, then confirm attack metrics fall while challenge pass rate, verified conversion, and 'cannot sign in' support tickets stay within baseline.

The common mistake it prevents

Keying every limit on IP address alone, which residential proxy pools walk straight through while shared mobile and office NATs lock out legitimate users.

~/.claude/skills/bot-fraud-defense/SKILL.md

--- name: bot-fraud-defense description: Defends signup, login, checkout, and content endpoints against automated abuse - credential stuffing, fake account creation, card testing,… license: MIT ---

Done well means: each abused flow has a named attack, a cost you are protecting (accounts, SMS spend, chargebacks, infra), layered controls that escalate friction only for risky traffic, decisions logged with their signals, and a dashboard that shows both attack volume and legitimate-user friction. A CAPTCHA on every form is not a defense plan; it taxes real users and is solved by paid farms for fractions of a cent.

Ground rules

  • Defensive only: build detection and friction for systems the user operates. Do not build or test against third-party sites, and do not write tooling that evades other sites’ bot protections.
  • Measure before you block. Ship new rules in log-only (shadow) mode for at least a few days, then compare flagged traffic with known-good cohorts.
  • Never reveal which signal triggered a block in the response; return generic errors and log the reason server-side.
  • Device fingerprinting and IP reputation involve personal data in the EU and elsewhere; document purpose (fraud prevention), retention, and disclose it in the privacy notice (see gdpr-privacy).
  • Accessibility: every challenge needs a non-visual path and a human fallback (support contact, email verification) for users who fail it.

Workflow

- [ ] 1. Name the attack and its cost from logs and bills
- [ ] 2. Map the flow: endpoints, identifiers, what the attacker gains per request
- [ ] 3. Baseline metrics (success/failure ratios, velocity, geography, ASN mix)
- [ ] 4. Choose layered controls from the decision table
- [ ] 5. Ship in shadow mode, tune, then enforce with progressive friction
- [ ] 6. Monitor attack and friction metrics; review weekly while active

1–3. Identify and baseline

Questions to answer from logs (see security-logging for the event schema):

  • Login: failed-login ratio per hour, distinct usernames per IP and per ASN, share of attempts on non-existent accounts (high share means a combo list).
  • Signup: signups per hour, email domain distribution, verification completion rate, time from page load to submit, activation within 7 days.
  • SMS/OTP: sends per destination country and prefix, OTP completion rate (pumping shows many sends with almost no completions to premium-rate ranges).
  • Checkout: authorization attempts per card BIN and per customer, decline rate by decline code (card testing shows many small auths with card_declined/incorrect_cvc).
  • Scraping: requests per session for listing/detail pages, ratio of HTML to asset loads, pagination depth, user agents claiming browsers without executing JS.

4. Decision table

AttackFirst controlsEscalationAvoid
Credential stuffingLimits per account and per IP/ASN on failures; breached-password check at signup, login, reset; identical error and timing for bad user vs bad passwordInvisible challenge for risky logins; step-up MFA on new device; passkeysHard account lockout (attackers use it to lock real users out)
Fake signupsEmail verification before privileges; disposable-domain blocklist; normalized-email uniqueness; honeypot field and minimum fill timeTurnstile on signup; phone verification only for high-value tiersPhone verification for everyone (cost, SMS pumping surface)
SMS pumping / toll fraudAllowlist SMS destination countries you serve; per-number, per-IP, per-prefix send caps; require a challenge before the first SMSProvider fraud guard features; switch to email, TOTP, or passkeysUnlimited “resend code” buttons
Card testingRequire login or a challenge before payment; velocity per customer, IP, and card fingerprint; processor risk rules (e.g. Stripe Radar)Block BIN ranges under attack temporarily; 3DSExposing a public “$1 donation” form without limits
Promo / trial abuseOne redemption per normalized email, payment fingerprint, and device; delay reward until activationManual review queue above a thresholdRelying on IP alone (shared NAT, mobile carriers)
ScrapingAuth or signed tokens for bulk data endpoints; per-session and per-key quotas; cache and paginate with cursors; robots.txt for honest crawlersEdge bot management (managed challenge, JS detection); serve stale or partial data to flagged sessionsBlocking by user agent string alone

Rate-limit mechanics (algorithms, Redis, headers) belong to rate-limiting; this skill decides what to key on and when to escalate.

Signals worth collecting

SignalCheap?Notes
Velocity per account, IP, /24 or /64, ASN, email domain, deviceYesCombine keys; residential proxy pools defeat per-IP limits alone
ASN type (hosting vs residential vs mobile)Yes, with an IP data feedDatacenter ASNs on consumer login pages are suspicious, but VPN users are real customers
Account age, verified email, prior successful logins from this deviceYesBest “known good” signals; use them to reduce friction
Breached password (Pwned Passwords k-anonymity)YesBlock at signup/reset, force reset at login
Form timing, honeypot, JS executionYesCatches unsophisticated bots only
Challenge result (Turnstile, hCaptcha, reCAPTCHA)Low costA risk signal, not proof of humanity
TLS/HTTP fingerprint (e.g. JA4) from your edgeDepends on CDNUseful for clustering automation; mismatched UA and fingerprint is a strong signal
Device attestation (App Attest, Play Integrity)MobileServer-verified only

Score, do not single-gate: risk = weighted sum of signals, mapped to allow / challenge / step-up / block / review. Keep weights in config so they change without deploys.

Breached password check (k-anonymity)

import hashlib, urllib.request

def pwned_count(password: str) -> int:
    sha1 = hashlib.sha1(password.encode()).hexdigest().upper()
    prefix, suffix = sha1[:5], sha1[5:]
    req = urllib.request.Request(
        f"https://api.pwnedpasswords.com/range/{prefix}",
        headers={"Add-Padding": "true", "User-Agent": "example-app-auth"},
    )
    with urllib.request.urlopen(req, timeout=3) as resp:
        for line in resp.read().decode().splitlines():
            s, _, count = line.partition(":")
            if s == suffix:
                return int(count)
    return 0

Only the 5-character hash prefix leaves your server. Fail open with a logged warning if the API is unreachable at login; fail closed (ask for another password) at signup only if your UX tolerates it.

Server-side challenge verification (Turnstile)

// The widget token is single-use and expires after about 5 minutes.
export async function verifyTurnstile(token: string, ip: string, expectedAction: string) {
  const body = new URLSearchParams({
    secret: process.env.TURNSTILE_SECRET_KEY!, // never ship the secret to the client
    response: token,
    remoteip: ip,
  });
  const res = await fetch("https://challenges.cloudflare.com/turnstile/v0/siteverify", {
    method: "POST",
    body,
    signal: AbortSignal.timeout(3000),
  });
  const data = (await res.json()) as { success: boolean; hostname?: string; action?: string; "error-codes"?: string[] };
  return data.success && data.hostname === "app.example.com" && data.action === expectedAction;
}

Always verify on the server; a client-side “solved” flag proves nothing. Check hostname and action so tokens minted on another page cannot be replayed here.

CAPTCHA choice

OptionChoose whenTradeoff
Cloudflare TurnstileDefault for most apps; invisible or managed mode; no image puzzlesRequires calling Cloudflare; works without using Cloudflare as CDN
hCaptchaYou want an alternative vendor or its enterprise risk scoresVisible puzzles more often in free tier
reCAPTCHA (v3 / Enterprise on Google Cloud)Already on Google Cloud and want score-based assessmentScores need threshold tuning; check current pricing and key migration to Cloud projects
Proof-of-work challenge (self-hosted)Cannot send data to third partiesRaises cost for bots modestly; burdens low-end devices
None, rely on signalsLow-value forms with good rate limitsFine until an attacker targets you

5. Progressive friction and enforcement

  1. Shadow: compute risk, log decision, take no action.
  2. Challenge high-risk only (invisible first, interactive second).
  3. Step-up for account actions: MFA or email confirmation on new device plus risk.
  4. Block or tarpit clearly malicious clusters (slow responses, generic errors).
  5. Review queue for money-moving actions where false positives are expensive.

Credential stuffing specifics: notify users of successful logins from new devices; force password reset for accounts where a stuffing attempt succeeded; invalidate their sessions. Offer and promote passkeys (see passkeys-webauthn), which remove the password reuse problem entirely.

6. Metrics and review

Track per flow, daily: attempts, blocked, challenged, challenge pass rate, false-positive reports (support tickets tagged “can’t sign in”), verified conversion rate for challenged versus unchallenged users, cost (SMS spend, chargebacks). Alert on failed login ratio and SMS sends per country exceeding baseline by a set multiple.

Output contract

# Abuse defense plan: <flow>
**Attack:** <what, since when, volume>   **Cost:** <$ / accounts / infra>
**Signals in use:** <list with weights>
**Controls:** <limit keys and thresholds> | <challenge placement> | <step-up>
**Rollout:** shadow <dates> -> enforce <date>; kill switch: <flag name>
**Success metrics:** <attack metric target> while <friction metric stays under X>

Gotchas

  • Per-IP limits alone fail against residential proxies and hurt carrier-grade NAT users; always pair with per-account and per-identifier keys.
  • Normalizing emails (lowercase, strip +tag, Gmail dots) stops trivial duplicates; apply it for uniqueness checks, but still send mail to the address the user typed.
  • Distinct error messages for “no such user” turn login and reset into enumeration oracles; keep responses and timing identical.
  • Challenge tokens verified only on the first step of a multi-step flow let bots replay the later steps directly; bind the verification to the session and the action.
  • Blocking whole countries or hosting ASNs blocks real customers on VPNs and corporate egress; prefer challenge over block for those segments.

About this skill

Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.

esc