SecureBlockLog inStart a pentest
Vulnerability Repository
MediumInjection

Host Header Injection

Trusting the HTTP Host header without validation enables password reset poisoning, cache poisoning, SSRF, and web cache attacks via attacker-controlled domain injection.

CVSS 6.5CWE CWE-644OWASP A03:2021 — Injection

Description

The HTTP Host header tells a web server which virtual host or application the request is intended for. Web applications frequently use the Host header value to construct absolute URLs in responses—password reset links, email confirmation links, redirect targets, and API base URLs. When an application trusts and uses the Host header without validating it against a whitelist of allowed hostnames, attackers can supply an arbitrary value and cause the application to generate URLs pointing to attacker-controlled infrastructure.

CWE-644 (Improper Neutralization of HTTP Headers for Scripting Syntax) captures this class of header injection. A03:2021 Injection applies because the attacker is injecting a malicious value into a header that is subsequently used in application logic without sanitization. Host header injection is particularly insidious because it exploits trusted application functionality—the password reset feature—rather than requiring a separate XSS or injection point.

Password reset poisoning is the most critical real-world exploitation scenario. The application sends a password reset email containing a link like https://[Host-header-value]/reset?token=<token>. If the victim clicks this link, they contact the attacker's server, which receives the token. The attacker can then use the token to reset the victim's password.

How It Works

A standard password reset flow with a vulnerable Host header trust:

POST /reset-password HTTP/1.1
Host: attacker.example.com
Content-Type: application/x-www-form-urlencoded

email=victim@example.com

The application generates a reset email with the attacker's domain in the link:

Subject: Reset your password
From: noreply@example.com
To: victim@example.com

Click here to reset your password:
https://attacker.example.com/reset?token=a1b2c3d4e5f6

When the victim clicks the link, their browser sends the request to attacker.example.com, delivering the token. The attacker captures it and resets the victim's password:

# Attacker's HTTP log shows:
GET /reset?token=a1b2c3d4e5f6 HTTP/1.1
Host: attacker.example.com

Additional attack variants use X-Forwarded-Host and X-Host as bypass headers when the application preferentially trusts override headers:

POST /reset-password HTTP/1.1
Host: example.com
X-Forwarded-Host: attacker.example.com

email=victim@example.com

Penetration testers test Host header injection using Burp Suite's Collaborator to receive out-of-band DNS and HTTP callbacks:

POST /reset-password HTTP/1.1
Host: <burp_collaborator_subdomain>.burpcollaborator.net

email=victim@example.com
# Check Collaborator for DNS/HTTP interaction — confirms server used the injected host

Web cache poisoning via Host header injection occurs when the cache key does not include the Host header but the response body reflects it as an absolute URL—poisoning the cache with the attacker's domain for all subsequent users.

Impact

  • Account takeover via password reset poisoning — Victims' password reset tokens are delivered to attacker-controlled servers.
  • Web cache poisoning — Host header reflection in cached responses poisons the cache with attacker-controlled URLs.
  • Server-side request forgery — Internal routing systems that trust the Host header to determine forwarding destinations can be redirected to internal services.
  • Password reset link spoofing — Even without token theft, poisoned links redirect users to phishing pages after authenticating with a valid token.
  • CORS bypass — Applications that dynamically build Access-Control-Allow-Origin values from the Host header can be manipulated to permit cross-origin access.

Detection

  1. Intercept a password reset request and modify the Host header to a Burp Collaborator subdomain; trigger the reset and check whether the Collaborator receives a DNS or HTTP interaction.
  2. Test X-Forwarded-Host, X-Original-Host, X-Host, and Forwarded: host= headers as alternate injection vectors for applications that preferentially trust proxy headers.
  3. Test double Host headers: some HTTP parsing libraries use the second value, while others use the first—Host: example.com\r\nHost: attacker.com.
  4. Check whether password reset links in received emails contain the value of the injected Host header rather than the application's actual domain.
  5. Test with an absolute URL in the Host header: Host: example.com@attacker.com or Host: attacker.com#example.com.

Remediation

Validate the Host header against a whitelist. Maintain a list of allowed hostnames and reject or sanitize requests where the Host value does not match:

ALLOWED_HOSTS = ['example.com', 'www.example.com', 'api.example.com']

def get_safe_host(request):
    host = request.headers.get('Host', '').split(':')[0]
    if host not in ALLOWED_HOSTS:
        raise ValueError(f"Invalid host: {host}")
    return host

Hardcode the application's base URL for security-sensitive operations. Password reset links, email confirmation URLs, and any security-critical URLs should be constructed from a hardcoded configuration value, never from the Host header:

BASE_URL = settings.APPLICATION_BASE_URL  # "https://example.com"
reset_link = f"{BASE_URL}/reset?token={token}"

Strip and distrust forwarding headers. Unless operating behind a trusted reverse proxy, strip X-Forwarded-Host, X-Original-Host, and X-Host headers at the ingress point before requests reach the application.

Ready when you are
Scope a pentest in the next two minutes.
Start scoping