Password Reset Poisoning via Host Header: Steal the Token From the Email
General Host-header writeups cover cache keys and redirects. This one is narrower: the app builds the password-reset URL from the request host, puts that URL in an email, and the token rides along. Whoever receives the HTTP hit to that host gets the reset secret.
You are not looking for a reflected Host string on an error page. You are looking for a poisoned link in your own mailbox.
Why reset emails are special
Reset tokens are single-purpose credentials. If the email says https://attacker.tld/reset?token=… (or a path the attacker’s server logs), the victim never needs to click a phishing page you designed — the legitimate product emailed them the wrong origin.
That is account takeover with one forged header, assuming the victim requests a reset (or you can trigger reset for addresses you control during the PoC). Broader Host-injection articles stop at “header reflected.” Here the deliverable is the token in transit via email infrastructure you do not control — only the URL host.
Headers that actually matter
Test systematically, one change at a time:
Host: attacker.tldHost: legit.tldplusX-Forwarded-Host: attacker.tldX-Forwarded-Hostalone when a reverse proxy is in frontForwarded: host=attacker.tldon stacks that honor RFC 7239- Absolute-form request lines if the edge preserves them
- Duplicate
Hostheaders where parsers disagree
Some stacks take Host for routing but X-Forwarded-Host for URL generation. Others ignore forged Host entirely after the load balancer rewrites it — those are usually clean. When a CDN sits in front, try the origin hostname only if the program allows direct-to-origin tests; otherwise stick to the public site with poisoned forwarded headers.
Proof on accounts you own
- Capture the reset-request API (
POST /forgot-passwordor similar). - Replay it for your test email with a poisoned host header.
- Open the email. If the link host is yours, visit it (or log the query) and complete the password change on your account.
- Show before/after: token landed on your listener, password changed, old sessions behavior.
Never request resets for strangers to “prove” interception. Your inbox is enough. If the email still points at the real domain but embeds your host in a tracking parameter, check whether that parameter is trusted on click — sometimes the open-redirect half finishes the chain.
Edge cases that still pay
- App uses a configured domain for most links but a template partial still concatenates
Hostfor the token path - Mobile deep links:
app://schemes mixed withhttps://hosts built from headers - Multi-tenant SaaS where the reset host is
{tenant}.product.comand a forged host still carries a valid token query - Reset confirmation pages that bounce through an open redirect after the token is accepted
- Passwordless magic links that reuse the same URL builder as resets
Also check whether the token is bound to the host. If redeeming on legit.tld works even when the email pointed at you, impact may be phishing-only — still report, but severity drops unless you can show the token leaked via Referer to your domain’s resources.
What triagers want in the report
Exact request (headers redacted where needed), screenshot or copy of the emailed URL with your domain, and confirmation you changed your password via that token. Recommend building reset URLs from a server-side canonical origin, ignoring client-supplied host/forwarded headers for link generation, and binding tokens to account + purpose with short TTL.
PortSwigger documents this pattern under password reset poisoning. Treat Host injection elsewhere as a separate finding unless it feeds the same email path.