Understanding HTTP Host Header Attacks With Easy Examples

Understanding HTTP Host Header Attacks With Easy Examples

Understand HTTP Host header attacks and how to prevent them. Protect your web app from password reset and redirect vulnerabilities.

The HTTP Host header looks harmless, but when an application trusts it too much, it can lead to account hijacking, cache poisoning, SSRF, and even internal routing bypasses. This guide explains the attack in detail - including the part most people misunderstand: the attacker does not need DNS control.


What Is the Host Header?

Every HTTP/1.1 request includes a header called Host:

GET / HTTP/1.1
Host: example.com

Its purpose is simple: Tell the server which domain the client wants.

But there’s a catch: The server blindly trusts whatever is written there. It never checks DNS to verify it.


Why Is This Dangerous?

Because many applications use the Host header to:

  • Build absolute URLs
  • Generate links in emails (verification, reset, confirmation)
  • Do tenant selection in multi-domain setups
  • Create redirect targets
  • Form cache keys
  • Detect “current domain” for business logic

If the attacker can change the header, they can influence all of these features.


How an Attacker Actually Exploits It (Step by Step)

This is the part that confuses people, so let’s make it crystal clear.

1. The attacker does NOT hack your DNS

  • No domain spoofing.
  • No /etc/hosts.
  • No Wireshark magic.

They just need your server's IP (which is usually trivial to find).


2. They send a request directly to your IP

Example:

POST http://203.0.113.10/forgot-password
Host: evil.com
Email: [email protected]

Routing depends on the IP, not on the Host header, so your server accepts it normally.


3. Your server trusts the Host value

If your app does something like:

const base = `https://${req.headers.host}`;

Then the password reset link becomes:

https://evil.com/reset?token=ABC123

Your own server sends the poisoned link.

Victim sees:

Reset your password: https://evil.com/reset?token=ABC123

They click it.


5. Token goes straight to the attacker

Because evil.com is attacker controlled.

The attacker now owns the victim’s reset token and can change the password on the real site.


Other Attack Scenarios

1. Web Cache Poisoning

If your cache key includes the Host header:

Host: fake.com

The response gets stored under a weird key and may leak into the main cache path.


2. Internal Routing Bypass

Misconfigured virtual hosts sometimes route unexpected Host values to:

  • Admin panels
  • Internal dashboards
  • Debug servers

3. SSRF via Host Header

Some apps make internal requests like:

curl http://$HOST/status

If $HOST comes from the Host header, the attacker can force internal requests to:

  • 127.0.0.1
  • Internal admin services
  • Metadata endpoints (e.g., AWS 169.254.169.254)

Why This Works (The Core Concept)

  • HTTP does not validate the Host header: It doesn't check DNS.

  • Servers route based on IP, not Host: If the request reaches your IP, your app processes it normally.

  • Any HTTP client can change the Host header: curl, Burp, Postman, or custom scripts.

That’s why the attack is trivially easy.


How to Prevent Host Header Attacks

1. Whitelist Allowed Hosts

Reject requests where Host is not one of your domains.

Node.js example:

const allowed = ["example.com", "www.example.com"];

app.use((req, res, next) => {
  const host = req.headers.host?.split(":")[0];
  if (!allowed.includes(host)) return res.status(400).end();
  next();
});

Go example:

allowed := map[string]bool{
    "example.com": true,
    "www.example.com": true,
}

2. Never Generate URLs From req.headers.host

Use environment variables or configuration values.

Example:

APP_URL=https://example.com

3. Configure Reverse Proxies Correctly

Nginx:

server_name example.com www.example.com;

Disable wildcard hosts and avoid forwarding unvalidated Host headers upstream.


4. Enable Framework Features

Most modern frameworks already have protections:

  • Django → ALLOWED_HOSTS
  • Rails → config.hosts
  • Symfony → trusted hosts config
  • Laravel → trusted proxies

Use them.


5. Log Suspicious Host Values

Anything outside your known domain list should be logged and inspected.


Final Thoughts

HTTP Host header attacks seem simple, but they can break critical parts of your application - especially password resets, redirects, and multi-tenant logic. The trick works because web servers trust the Host value even though it’s 100% user-controlled.

Validate the header, avoid using it for important logic, and tighten your proxy configuration. That’s all it takes to block this entire class of vulnerabilities.


Album of the blog: