Safeguard
Security Guides•

Why shouldn't password reset links use the Host header?

If your reset email builds its link from the request Host header, an attacker can aim the link at their own site. Hard code the base URL instead.

Safeguard Security Team
3 min read

Because the Host header is supplied by the requester. If your app builds the reset link in the email from it, an attacker can request a reset for a victim with a forged Host value, and the victim receives a genuine email whose link points to the attacker's server. Use a fixed base URL.

Definition

Host header injection in password reset, sometimes called reset poisoning, is a flaw where the application trusts the Host header, or a similar forwarded header, to compose absolute URLs. The OWASP Forgot Password Cheat Sheet says not to rely on the Host header when creating reset URLs, to avoid Host Header Injection, and to hard code the base URL or validate it against a list of trusted domains.

How the attack plays out

  1. The attacker submits a reset request for the victim's address and changes the Host header to a domain they control.
  2. Your server creates a valid token and emails the victim a link built from the forged host.
  3. The victim opens the email, which really came from you, and clicks.
  4. The link leads to the attacker's server, which captures the token, then uses it on your real site.

Many users click because the email passes every authentication check. That is why a fix in email authentication does not help here. The bad part is inside your own message.

Related header trouble

Reverse proxies add forwarded host headers. If your framework trusts them from any client, the same problem returns through a different header. Trust forwarded values only from your own proxy. See trusting proxy headers safely.

Other reset link rules from OWASP

RuleWhy
Consistent response for known and unknown accountsAvoids confirming which accounts exist
Cryptographically secure tokens, long enough to resist brute forcePrevents guessing
Single use and expiryLimits the value of a stolen link
HTTPS linksProtects the token in transit
No-referrer policy on the reset pageStops the token leaking to third party resources
Rate limit requestsPrevents flooding a user's inbox

Steps

  1. Search your code for any place a URL is built from the request host, in emails especially.
  2. Replace it with a configuration value for the public base URL per environment.
  3. If you host many tenants, validate the host against an allow list before using it.
  4. Configure your framework's allowed hosts setting. See Django ALLOWED_HOSTS explained.
  5. Add a test that sends a forged Host header and asserts the emailed link still uses your domain.
  6. Review other email links, such as invites and confirmations, with the same test.

Where Safeguard fits

Safeguard's web application scanning (DAST) and code scanning help find places where request headers flow into generated links, and its dependency scanning flags framework versions with known issues. The free scan is at https://gold.safeguard.sh/scan.

Try it yourself

Click through it at your own pace, or open it full screen.

Quick check

Does SPF, DKIM and DMARC stop this attack?

No. The email is genuinely sent by you. The harmful link is built by your own code.

What replaces the Host header?

A configured base URL, or a host checked against a list of trusted domains.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.