Skip to main content

Free 30-min security demo  — We'll scan your real code and show live findings, no commitment Book Now

Offensive360
Academy Host Header Injection
Intermediate · 20 min

Host Header Injection

Learn how attacker-controlled Host headers poison password reset links and web caches.

1 Host Header Attack Scenarios

The HTTP Host header specifies which virtual host to serve. When applications trust the Host header to construct absolute URLs (like password reset links), attackers who control the header can redirect sensitive links to their own server.

Password reset link poisoning:

# Vulnerable: trusts Host header for reset URL
def send_reset_email(user):
    host = request.headers.get("Host")  # Attacker-controlled!
    reset_url = f"https://{host}/reset?token={token}"
    send_email(user.email, reset_url)
    # Victim receives: https://attacker.com/reset?token=REAL_TOKEN
    # When victim clicks, attacker captures the token!

Cache poisoning via Host:

If a caching layer uses the Host header as a cache key component and the application reflects it in the response (e.g., in a self-referential URL), an attacker can poison the cache with a malicious Host value that affects other users.

The attack requires the ability to set the Host header, possible via a proxy misconfiguration or HTTP request smuggling.

2 Validate Host Against Allowlist

The fix is to never trust the Host header for security-sensitive URL construction. Instead, use a configured allowlist of valid hostnames.

Django: ALLOWED_HOSTS setting:

# settings.py
ALLOWED_HOSTS = ["myapp.com", "www.myapp.com"]
# Django validates the Host header against this list
# Requests with unauthorized Host headers return 400

Custom host validation:

ALLOWED_HOSTS = {"myapp.com", "www.myapp.com"}

def get_base_url():
    # Never use request.headers["Host"] for security-sensitive URLs
    # Use a configured value instead
    return "https://myapp.com"

def send_reset_email(user, token):
    reset_url = f"{get_base_url()}/reset?token={token}"
    send_email(user.email, reset_url)

Defense checklist:

  • Configure ALLOWED_HOSTS / trusted hosts in your framework
  • Never use the Host header to construct absolute URLs in email
  • Configure a static base URL from environment variables
  • Use X-Forwarded-Host carefully — only from trusted proxies

Knowledge Check

0/3 correct
Q1

How does Host header injection enable password reset token theft?

Q2

What is the safest way to determine your application's base URL for constructing absolute links?

Q3

Django's ALLOWED_HOSTS setting mitigates Host header injection by doing what?

Code Exercise

Use Configured Base URL

The password reset email uses the Host header to construct the reset link. Fix it to use a configured BASE_URL environment variable instead.

python