Security Cipher

Security Resources

⌘K
  1. Home
  2. Security Resources
  3. Vulnerability Explain
  4. Host Header Injection

Host Header Injection

In this Vulnerability Explain post we cover Host Header Injection. The HTTP Host header seems harmless, but many applications trust it to build absolute URLs and route requests. When that trust is misplaced, attackers can poison password reset links, caches, and more. Let’s break it down.

What is Host Header Injection?

Host Header Injection occurs when an application uses the value of the Host (or related) header from the incoming request without validation – for example to build links, route to virtual hosts, or make security decisions.

Consider a password reset feature that emails a link built from the Host header. If an attacker sends a reset request with Host: evil.com, the victim receives a reset link pointing at the attacker’s domain. When they click it, the secret token leaks to the attacker.

How does Host Header Injection work?

Host header injection turns a trusted header into an attack like this:

  • App Trusts the Host Header
    • The application reads the incoming Host header to build URLs or route requests.
  • Attacker Forges the Header
    • The attacker sends a request with a Host value pointing at their own domain.
  • Poisoned Output
    • Generated links, emails, or cached pages now contain the attacker’s domain.
  • Victim Interaction
    • A victim clicks a poisoned password reset link or receives a poisoned cached response.
  • Impact
    • Outcomes include account takeover via leaked reset tokens, web cache poisoning, and routing-based bypasses.

The Host header is attacker-controlled like any other request input. Trusting it to build security-sensitive output is the mistake at the heart of this bug.

Host header injection diagram showing a forged Host header poisoning a password reset link

How Host header injection works: a forged Host header poisons generated links like password resets.

Tools and Techniques for Host Header Injection Testing

Testing centers on supplying unexpected Host and related headers and observing the output.

Manual Testing Methodologies

  • Host Override – Change the Host header to an external domain and check generated links, especially password reset emails.
  • Duplicate and Ambiguous Hosts – Send two Host headers or an absolute request line to find inconsistent parsing.
  • Override Headers – Try X-Forwarded-Host, X-Host, and X-Forwarded-Server to see if they influence link building.
  • Cache Interaction – Check whether a poisoned Host value gets cached and served to others.

Automated Scanning Tools

  • Burp Suite Scanner – Detects Host header injection and related issues.
  • Nuclei – Templates probe Host and override headers.
  • httpx – Helps test how hosts respond to varied Host headers at scale.
  • OWASP ZAP – Free scanner with header manipulation support.

Host Header Injection Protection Mechanisms

Best Practices for Secure Coding

  • Do Not Trust the Host Header
    • Description: Build absolute URLs from a server-side configured domain, not the request header.
    • Benefits: Poisoned links become impossible.
    • Implementation Tip: Store the canonical base URL in configuration.
  • Validate Against an Allowlist
    • Description: If you must read the Host, validate it against approved domains.
    • Benefits: Rejects forged values.
    • Implementation Tip: Reject requests whose Host is not on the list.
  • Secure Reset Tokens
    • Description: Make password reset links robust even if a domain is wrong.
    • Benefits: Limits damage from any link poisoning.
    • Implementation Tip: Use short-lived, single-use tokens bound to the user.

Best Practices for Organizations

  • Web Server Hardening
    • Configure the server to reject requests with unexpected Host values.
    • Define a default server block that drops unknown hosts.
  • Cache Configuration
    • Ensure caches key on a validated host.
    • Avoid caching responses that reflect the Host header.
  • Testing
    • Test password reset and link generation with forged hosts.
    • Add Host header checks to security reviews.

Top Host Header Injection payloads used by Security Researchers

As a security researcher, knowing the most common payloads helps you detect and prevent these attacks. Use this knowledge ethically and only on systems you are authorized to test. Some sample payloads are shown below.

// Forged Host header to poison a reset link
POST /reset HTTP/1.1
Host: evil.com

email=victim@example.com
// Override header variant
GET /reset HTTP/1.1
Host: legit.com
X-Forwarded-Host: evil.com
// Duplicate Host headers (ambiguous parsing)
Host: legit.com
Host: evil.com
// Absolute request line
GET https://evil.com/reset HTTP/1.1
Host: legit.com

Real-World Example: Account Takeover via Reset Link

A web app generated password reset emails using the request’s Host header to build the link, trusting it implicitly.

A tester requested a reset for a victim’s account while sending Host: attacker.com. The victim received an email whose reset link pointed at attacker.com but still carried the valid token. Clicking it sent the token to the attacker, enabling account takeover.

The fix built reset links from a configured canonical domain and validated the Host header against an allowlist. The Host header is just more user input – never let it shape security sensitive output.

Vulnerable and secure code of Host Header Injection

The following example shows the contrast between vulnerable and secure code for Host Header Injection. It helps you see how the flaw creeps into real code and the changes that shut it down.

🥺 Vulnerable Code:

# Vulnerable: reset link built from the request Host header
@app.route("/reset", methods=["POST"])
def reset():
    email = request.form["email"]
    token = create_reset_token(email)
    host = request.headers.get("Host")  # attacker-controlled
    link = f"https://{host}/reset/confirm?token={token}"
    send_email(email, link)
    return "Reset email sent"
  • The Host header comes from the attacker and is placed directly into the link.
  • A forged Host sends the valid reset token to a domain the attacker controls.

😎 Secure Code:

# Secure: build links from a configured canonical domain
BASE_URL = "https://app.example.com"  # from trusted configuration

@app.route("/reset", methods=["POST"])
def reset():
    email = request.form["email"]
    token = create_reset_token(email)  # short-lived, single-use
    link = f"{BASE_URL}/reset/confirm?token={token}"
    send_email(email, link)
    return "Reset email sent"
  • The link uses a server-side base URL, so the Host header cannot poison it.
  • Short-lived, single-use tokens further limit any damage.

Conclusion

Host Header Injection is a classic case of trusting input that does not look like input. Build absolute URLs from a configured canonical domain, validate the Host against an allowlist when you must read it, harden the web server to reject unknown hosts, and keep reset tokens short-lived and single-use. The Host header is attacker-controlled – treat it that way.

How can we help?