HTTP Host Header Attacks
A complete guide to understanding, detecting, exploiting, and preventing HTTP Host Header Attacks vulnerabilities.
Introduction
HTTP HOST HEADER ATTACKS
A complete ANAS EDUCATION course on the bug class that lives inside one tiny header.
SECTION 1. Introduction
Imagine you open your PC and visit `anastech.com`.
You forgot your password. You click "Forgot password". A page appears with one text box:
You type your email and click "Send reset link".
In the next half-second, three things happen:
- ●Your browser sends an HTTP request to the server.
- ●The server reads your email, generates a secret token, and saves it in the database.
- ●The server emails you a link that includes that token.
The HTTP request your browser sent looks like this:
Notice the second line: `Host: anastech.com`.
The `Host` header tells the server which website you want. One server can host many websites (anastech.com, anasbank.com, anasmarket.com), so the `Host` header is how the server knows which one to reply about.
A few seconds later, you get an email:
You click the link. You type a new password. Done.
Look at the link in the email carefully:
Most developers write the reset email like this:
The developer reads the `Host` header from your request and pastes it into the email.
That feels safe. The `Host` header is part of HTTP. The browser sets it. The user does not type it.
Now look at the same picture again, but with a question on top of it:
- ●What if you do not send `Host: anastech.com`?
- ●What if you send `Host: attacker.com`?
You can. The Host header is just text in a request. You can change it with any tool: Burp Suite, curl, Python, Postman.
If the server trusts the Host header, the email goes out with:
The victim user receives that email. They see "anastech.com" in the subject. They trust it. They click the link.
The browser sends the secret token to `attacker.com`.
The attacker now resets the victim's password.
That is the simplest possible HTTP Host header attack. It is called password reset poisoning.
But it is only one of seven famous attacks built from this one header. The other six let you:
- ●Bypass admin authentication by setting `Host: localhost`.
- ●Poison the CDN cache so every visitor gets a malicious link.
- ●Reach internal servers via routing-based SSRF.
- ●Hide payloads using ambiguous duplicate Host headers.
- ●Smuggle Host through `X-Forwarded-Host`, `X-Host`, `X-Forwarded-Server`.
- ●Bypass validation using connection state attacks.
This course teaches every one of them, slowly and completely.
By the end you will know:
- ●What the Host header really does in HTTP/1.1 and HTTP/2.
- ●How servers and proxies normally use it.
- ●The 25+ ways attackers exploit it.
- ●How to find each bug with curl, Burp, and Python.
- ●How to fix each bug at the application, framework, and proxy layer.
You do not need to be an expert. You just need to read carefully.
SECTION 2. How It Works
To find these bugs, you first need to understand the Host header in detail.
Step 1. Why the Host header exists
In the early 1990s, one server could serve only one website. If you ran the server, you owned the IP, you owned the site. Simple.
Then virtual hosting was invented. One server, one IP, many websites.
When your browser connects to `1.2.3.4`, the server has no way to know which of the four sites you wanted, unless your browser tells it.
That is the job of the `Host` header. HTTP/1.1 made it mandatory.
The server reads `anasbank.com` and routes the request to the right site.
Step 2. Who reads the Host header
The Host header is read by everyone in the chain:
Each layer can do something different with the Host header:
- ●The CDN uses it as part of the cache key so `anasmarket.com` and `anasdocs.com` are cached separately.
- ●The reverse proxy uses it to decide which back-end server gets the request.
- ●The back-end app uses it to build absolute URLs (the dangerous one).
Step 3. The mandatory and the dangerous use of Host
The Host header has one mandatory use:
- ●Routing the request to the right virtual host.
That use is safe because the server validates the Host against a list of sites it serves.
The dangerous use is when the application code reads the Host header at runtime to build URLs:
Each of these lines creates a way for an attacker who controls the Host header to control what the application generates.
Step 4. The normal flow on anastech.com
A safe request to forgot-password:
The email goes out with `https://anastech.com/reset?token=...`. Safe.
Step 5. The malicious flow
An attacker sends:
The Host header is `attacker.com` instead of `anastech.com`.
The victim receives the email. The victim clicks the link. The browser sends the secret token to `attacker.com`. The attacker resets the victim's password.
Step 6. The X-Forwarded-Host bypass
Most modern apps know about Host header attacks and check the Host header against a list. But many use a backup header.
When a request goes through a CDN, the CDN often replaces the Host header with the CDN's own hostname and stores the original in `X-Forwarded-Host`:
The back-end app uses `X-Forwarded-Host` to know the original site.
Now the attacker sends:
The app validates `Host: anastech.com` (passes). Then it reads `X-Forwarded-Host` to build the link. Same attack, different header.
The X-Forwarded-Host trick has variants:
- ●`X-Host: attacker.com`
- ●`X-Forwarded-Server: attacker.com`
- ●`X-HTTP-Host-Override: attacker.com`
- ●`X-Original-Host: attacker.com`
- ●`Forwarded: host=attacker.com`
Every one of these can override Host depending on the framework.
Step 7. The duplicate Host trick
HTTP/1.1 requires exactly one Host header. But many servers accept two.
The front-end validates the first one. The back-end uses the second one. Or vice versa. The result is the same: an attacker-controlled Host reaches the application.
Step 8. The line-folding trick
Some servers (older Apache, some Java parsers) honor obsolete line folding:
The leading space on line 3 makes it a continuation of the Host line. Some parsers concatenate `anastech.com attacker.com` and some get confused. A few use only the last token.
These are the four mechanical ways an attacker controls the Host as seen by the back-end. Every Host header attack technique in Section 11 is built from at least one of them.
SECTION 3. Attack Flow
This is the step-by-step flow of a complete account takeover via password reset poisoning. No characters, just steps.
Eleven steps. Zero characters with names. The attacker holds nothing fancy, just an HTTP request and a server that logs traffic.
The same flow with `X-Forwarded-Host: attacker.com` instead of `Host` works on apps that validate Host but not X-Forwarded-Host.
The same flow with `Host: anastech.com` and a poisoned cache works against every user of the site simultaneously (web cache poisoning).
SECTION 4. Why Developers Make This Mistake
This bug is older than most developers in the industry. Yet it still ships. Here is why.
Mistake 1. "The Host header is part of HTTP, so it must be trustworthy"
The Host header looks official. RFC 9110 requires it. Browsers always send it. Frameworks expose it as `request.host` or `request.url.host`.
Developers reason: "If the browser sends it, it must be the user's real domain."
This is wrong. Anyone with a TCP socket can send any Host header. curl, Python, Burp, Postman, custom scripts. The browser is one client among many.
Mistake 2. "Generating absolute URLs is the convenient way"
Building an email body like this is short and clean:
Building it with a hardcoded base URL feels redundant:
Developers reach for the convenient version because it works in dev, staging, and production without changing the code. The hardcoded version requires environment-specific config.
The convenient version is the vulnerable one.
Mistake 3. "We use a reverse proxy, the proxy will validate the Host"
In a multi-tier architecture, developers assume the proxy in front of them did the validation. The proxy operations team assumes the application did the validation. Neither does it. Result: a vulnerability that survived 5 code reviews because everyone thought it was someone else's job.
The classic "X-Forwarded-Host trusted from anywhere" bug lives here.
Mistake 4. "We tested with the browser, the Host header was correct"
Most developers only ever generate requests from their browser. The browser sends the right Host. Tests pass. Bugs ship.
You need to test with curl, Burp Repeater, or a Python script that lets you inject arbitrary headers. Most developers do not.
SECTION 5. Beginner Summary
- ●The `Host` header tells a server which website you want. One server can host many sites; the Host header picks the right one.
- ●Many apps read the Host header at runtime to build links (password reset emails, redirects, image URLs). If the attacker controls Host, the attacker controls those links.
- ●The classic attack is password reset poisoning: send a forgot-password request with `Host: attacker.com` and the victim receives an email pointing to attacker.com with their secret token.
- ●Other attacks include `Host: localhost` to bypass admin checks, `X-Forwarded-Host: attacker.com` to override validated Host, duplicate Host headers, and routing-based SSRF when the front-end forwards based on Host.
- ●The fix is to never use the Host header to build URLs. Hardcode the canonical domain in a config file. If you must use Host, validate it against an allow-list of permitted domains and reject everything else.
SECTION 6. Visual Explanation
Diagram 1. The safe pattern
The application uses a hardcoded base URL from configuration. The Host header is ignored for URL building.
Whatever Host header arrives in the request, the link always points to anastech.com.
Diagram 2. The vulnerable pattern
The application reads `request.host` (or `X-Forwarded-Host`) at runtime to build URLs.
The link inherits whatever Host the attacker sent.
Diagram 3. Headers an attacker can use
Diagram 4. Attack escalation ladder
Diagram 5. Where the Host header travels
The deeper the bug lives, the more layers an attacker has to trick to reach it.
SECTION 7. Definition
Technical definition
HTTP Host header attacks are a class of vulnerabilities in which an attacker manipulates the `Host` header (or related override headers such as `X-Forwarded-Host`) to cause the back-end application to make incorrect routing, validation, or content-generation decisions. The application reads the Host header at runtime to construct absolute URLs (password reset links, email contents, redirects, canonical tags), to authenticate or authorize requests (allow-listing localhost, internal IPs, or admin hostnames), or to route traffic to internal services. Because the Host header is attacker-controllable at the TCP layer, any trust placed in it without validation creates a vulnerability.
Primary classifications:
- ●CWE-20 (Improper Input Validation), umbrella for unvalidated Host.
- ●CWE-444 (Inconsistent Interpretation of HTTP Requests), when Host is interpreted differently by front-end and back-end.
- ●CWE-640 (Weak Password Recovery Mechanism for Forgotten Password), when used for password reset poisoning.
- ●CWE-918 (Server-Side Request Forgery), when the bug enables routing to internal hosts.
- ●CWE-345 (Insufficient Verification of Data Authenticity), when the Host is used to determine origin authority.
OWASP categories:
- ●A03:2021 - Injection (the Host value is injected into emails, URLs, headers).
- ●A05:2021 - Security Misconfiguration (proxy and framework defaults trust Host).
- ●A07:2021 - Identification and Authentication Failures (password reset poisoning).
- ●A10:2021 - Server-Side Request Forgery (SSRF) (routing-based variants).
Beginner definition
The Host header is a label on every HTTP request that says which website the user is asking for. If the app trusts that label without checking, the attacker can put anyone's name on the label and trick the app.
Why it matters in 2025-2026
- ●CVE-2025-52560 (Kanboard) ==> CWE-640. Kanboard password reset email URLs are derived from the unvalidated Host header when `application_url` is unset. Attackers send a poisoned forgot-password request and capture reset tokens.
- ●CVE-2024-46452 (open-source online shop) ==> Host Header Injection in the password reset function. Public 2024 disclosure.
- ●CVE-2024-40686 (IBM SmartCloud Analytics) ==> Host Header Injection enabling cache poisoning and session hijacking.
- ●CVE-2023-32314 (vm2 sandbox) ==> Host-based path detection bypass.
- ●CVE-2022-2812 (Authelia) ==> Allowed Host header bypass leading to redirect to attacker.
Every major framework has patched at least one Host header CVE in the last 36 months: Django, Flask, Express, Spring, ASP.NET Core, Rails, Laravel. The bug never dies because absolute URL generation never dies.
Common affected systems
- ●Password reset and account recovery features in any web application.
- ●Single sign-on (SSO) implementations using SAML or OAuth with redirect URIs derived from Host.
- ●Email notification systems (account creation, invitation, billing receipts).
- ●CDN-fronted applications (cache poisoning amplifies the bug).
- ●Multi-tenant SaaS platforms where Host determines tenant context.
- ●Admin panels that allow-list `localhost` or `127.0.0.1` without checking the network layer.
- ●Internal services exposed by routing-based logic that trusts Host.
- ●Frameworks that auto-generate absolute URLs from request context (Django `request.build_absolute_uri`, Spring `ServletUriComponentsBuilder`, Express `req.headers.host`).
SECTION 8. Examples
Example 1. The password reset on anastech.com
The feature. AnasTech has a forgot-password page. The user enters their email. The server sends a link with a secret token to that email. The user clicks the link, types a new password, and is logged in.
The bug. The Python back-end builds the email link from `request.headers["Host"]` instead of a hardcoded base URL.
The attack step by step.
- ●The attacker captures or guesses the victim's email (`carlos@gmail.com`).
- ●The attacker sends `POST /forgot-password` with `Host: attacker.com` and body `email=carlos@gmail.com`.
- ●AnasTech generates a token, stores it in the database, and sends the email.
- ●The email contains the link `https://attacker.com/reset?token=secret_T`.
- ●Carlos receives the email titled "AnasTech password reset" and clicks the link.
- ●Carlos's browser sends a GET to `attacker.com/reset?token=secret_T`.
- ●The attacker server logs the token, then redirects Carlos to the real site so Carlos sees nothing suspicious.
- ●The attacker visits `https://anastech.com/reset?token=secret_T`, sets a new password, and owns Carlos's account.
Example 2. The admin panel that trusts localhost
The feature. AnasCorp internal admin panel checks the Host header. If `Host == localhost` or `Host == 127.0.0.1`, the panel skips the login check because "only local processes can reach localhost".
The bug. The check happens at the application layer. The reverse proxy in front of the app forwards arbitrary Host headers without rewriting them.
The attack step by step.
- ●The attacker discovers `admin.anascorp.com` returns a login page on standard requests.
- ●The attacker changes the Host header to `localhost` and sends the same request.
- ●The reverse proxy forwards based on TLS SNI, not the Host header.
- ●The application sees `Host: localhost`, skips the login check, and renders the full admin panel.
- ●The attacker reads all employee data, creates a new admin user, and pivots to internal services.
Example 3. The CDN cache that gets poisoned
The feature. AnasMarket fronts its main site with a CDN. The CDN caches the homepage by path. The homepage contains absolute URLs to CSS, JavaScript, and images, built using `request.host`.
The bug. The CDN does not include the Host header (or the X-Forwarded-Host header) in the cache key for the homepage. The application includes whatever Host arrives in its generated HTML.
The attack step by step.
- ●The attacker sends `GET /` with `Host: anasmarket.com` and `X-Forwarded-Host: attacker.com`.
- ●The application uses `X-Forwarded-Host` to build the page, including `<script src="https://attacker.com/main.js">`.
- ●The response is cached by the CDN under key `/` for site `anasmarket.com`.
- ●Every subsequent visitor receives the poisoned homepage from cache.
- ●Each visitor's browser fetches and executes `attacker.com/main.js`.
- ●The attacker steals session cookies, runs cryptominers, or redirects to phishing pages.
Example 4. The routing-based SSRF on AnasBank
The feature. AnasBank has a multi-tier architecture. The edge proxy forwards based on TLS SNI to the same back-end pool. Each pool member uses the Host header to decide which application to invoke.
The bug. The proxy does not enforce that the Host header matches the SNI. The application back-end accepts any Host. Some internal hosts are only reachable via the back-end pool but use the Host header to identify themselves.
The attack step by step.
- ●The attacker sends a request to the public endpoint with `Host: internal-admin.local`.
- ●The proxy forwards based on SNI (which points to the public hostname).
- ●The back-end reads `Host: internal-admin.local` and routes the request internally.
- ●The attacker reaches the internal admin server that is not exposed to the internet.
- ●Same trick with `Host: 169.254.169.254` reaches the cloud metadata service.
Example 5. The dangling markup on AnasOne
The feature. AnasOne sends password reset emails using an HTML template. The email contains a `<base href="...">` tag generated from the Host header. The base tag tells the email client where to resolve relative URLs.
The bug. The Host header is inserted into the HTML without escaping. The reset link itself uses relative paths.
The attack step by step.
- ●The attacker sends a forgot-password request with `Host: x"><a href='//attacker.com/?`.
- ●The application generates HTML: `<base href="x"><a href='//attacker.com/?">`.
- ●The browser sees a complete `<base href="x">` and an `<a>` tag with attacker's URL.
- ●The legitimate reset link in the email is now rendered as an `<a>` tag pointing to attacker.com.
- ●The victim clicks the link expecting to reset the password but lands on attacker.com.
- ●Token leaks via the Referer header or via the URL fragment.
This variant is called password reset poisoning via dangling markup. It works even when the developer correctly URL-encodes the Host for the link but forgets to escape it for the surrounding HTML.
SECTION 9. Vulnerable Code
Python (Flask)
Python (Django)
PHP
Node.js (Express)
Java (Spring Boot)
C# (ASP.NET Core)
Ruby on Rails
NGINX (proxy misconfiguration)
The universal pattern across languages
Every vulnerable code sample above contains the same logical mistake:
- ●1. Trust placed in a request-controlled header. The Host header comes from the client; it cannot be trusted.
- ●2. Used without an allow-list. No check against a list of known good hostnames.
- ●3. Used to build something that gets shipped to other users (email, cached HTML, Location header).
- ●4. Side-effect outside the request. The bug only triggers because of email or cache, not the direct response.
- ●5. Framework feels safe. Developers use built-in helpers (`build_absolute_uri`, `ServletUriComponentsBuilder`, `req.hostname`) believing they are protected, but the helpers just pass through the Host header.
The pattern is identical to every other HTTP injection bug: untrusted input + no allow-list + downstream impact.
SECTION 10. Detection
Manual detection steps
- ●1. Identify every place the application generates an absolute URL: password reset emails, account verification, invitation links, email signatures, OAuth redirects, SAML responses, Location headers, OpenGraph meta tags, canonical links.
- ●2. For each absolute URL, capture a normal request in Burp Suite or curl.
- ●3. Change `Host: anastech.com` to `Host: attacker.com` (use a domain you control such as Burp Collaborator).
- ●4. Re-send the request.
- ●5. Read the response carefully. Look for `attacker.com` reflected in the body, in a header, or in a link.
- ●6. If the feature sends an email, trigger it with your own account and inspect the email body.
- ●7. If the feature redirects, watch the `Location:` header for `attacker.com`.
- ●8. If reflection appears anywhere, try `X-Forwarded-Host`, `X-Host`, `X-Forwarded-Server`, `Forwarded` instead of changing Host directly.
- ●9. Try `Host: localhost`, `Host: 127.0.0.1`, `Host: 169.254.169.254`, `Host: internal.local` to test for routing-based SSRF and authentication bypass.
- ●10. Try duplicate Host headers, indented Host headers, and absolute URI in the request line.
Burp Suite step by step
- ●1. Browse the application to capture the forgot-password request in Proxy ==> HTTP history.
- ●2. Right-click the request ==> Send to Repeater.
- ●3. In Repeater, switch the protocol to HTTP/1.1 (Inspector ==> Request attributes ==> Protocol). HTTP/2 makes Host editing tricky because of the `:authority` pseudo-header.
- ●4. Change the `Host:` value to `attacker.com` or your Burp Collaborator domain.
- ●5. Click Send. Read the response.
- ●6. If the email is the side effect, switch to your test email account, trigger the request, then check the inbox for the poisoned link.
- ●7. For X-Forwarded-Host testing, keep `Host: anastech.com` (so the front-end validator accepts) and add a new header `X-Forwarded-Host: attacker.com` below.
- ●8. To test routing-based SSRF, set `Host: 127.0.0.1`, `Host: 169.254.169.254`, or `Host: metadata.google.internal` and watch for different response sizes or error messages indicating the request reached a different back-end.
- ●9. Use the Burp Param Miner extension and right-click ==> Guess headers to discover undocumented override headers (`X-Backend-Host`, `X-Forwarded-Server`, etc.).
Common detection probes (one per technique)
Automated tools
- ●Burp Param Miner ==> guesses overrideable headers automatically. Right-click on a request ==> Extensions ==> Param Miner ==> Guess headers. Available as a Burp Suite extension.
- ●HostHunter ==> reconnaissance of virtual hosts and Host header behavior. https://github.com/SpiderLabs/HostHunter
- ●httpx by ProjectDiscovery ==> mass scan with `-host-header` flag for testing many targets. https://github.com/projectdiscovery/httpx
- ●nuclei with the host-header templates ==> `nuclei -t http/misconfiguration/http-host-header.yaml`. https://github.com/projectdiscovery/nuclei-templates
- ●ssrfmap ==> when host header attacks chain into SSRF. https://github.com/swisskyrepo/SSRFmap
Quick command-line scripts
Indicators of vulnerability
- ●Password reset emails that point back to the exact Host you sent in the request.
- ●Location headers that reflect arbitrary Host values.
- ●`<base href="...">` tags, canonical links, OpenGraph `og:url`, or Twitter Card `twitter:url` containing the request Host.
- ●Different response sizes when Host is `localhost`, `127.0.0.1`, or an internal IP.
- ●`502 Bad Gateway` or `504 Gateway Timeout` errors when Host is changed (indicates routing logic).
- ●Successful access to admin routes when Host is `localhost`.
- ●Cache hits (`X-Cache: HIT`) on pages that reflect headers.
Why the X-Cache header matters
When you request a page, the response can come from one of two places:
- ●Cache (a stored copy) ==> fast, shared copy kept by a proxy/CDN.
- ●Backend (the origin server) ==> the real website server.
Some proxies add an `X-Cache` header to tell you which happened:
The response came from the cache. The proxy had a stored copy and returned it directly. It did not contact the origin server. This is faster because the proxy served the saved response.
The proxy did not have a stored copy, so it went to the origin server, got the response, and usually stores that response in the cache for later requests.
In short: HIT = served from cache, MISS = fetched from origin.
This matters massively for Host header attacks. If you poison the cache (Section 11, technique 8), then every subsequent visitor receives the poisoned response with `X-Cache: HIT`. You can confirm a poisoning worked by sending two requests:
The HIT plus the attacker.com reflection proves the cache is poisoned. Every visitor for the cache TTL (often 30 seconds to several minutes) will receive the malicious response.
To probe whether a URL is cacheable at all, send the request twice and check if `X-Cache` flips from MISS to HIT:
Now add a query parameter:
If a different parameter value gives a new MISS, the parameter is part of the cache key. If the same parameter value (`test=124`) gives HIT on the second request, the cache key includes that exact path.
That mapping is essential for cache poisoning: find a header or parameter that the application reflects but the cache does not include in its key, and you can poison every key by manipulating that one input.
SECTION 11. Exploitation
Workflow
- ●1. Identify all features that generate absolute URLs (password reset, invites, redirects, OAuth, SAML).
- ●2. For each feature, capture a request in Burp.
- ●3. Try `Host`, then the 10 override headers from Section 6, then duplicate Hosts, then line folding, then absolute URI.
- ●4. If the application reflects your Host, confirm the impact: does it reach an email, a cache, a redirect, an internal service?
- ●5. Escalate: chain with cache poisoning, SSRF to cloud metadata, or authentication bypass.
- ●6. Build a clean PoC with a working attacker domain (Burp Collaborator, your own VPS, or interact.sh).
- ●7. Capture screenshots, request/response pairs, and the resulting email or cached response. These are the proof for your bounty report.
Advanced techniques
1. Basic password reset poisoning
The classic. Replace Host with attacker.com in the forgot-password request.
The victim receives an email with a link to `attacker.com`. They click; you capture the token.
2. Password reset poisoning via X-Forwarded-Host
The application validates `Host` against an allow-list but trusts `X-Forwarded-Host`.
The validation passes because Host is anastech.com. The application reads X-Forwarded-Host to build the link.
3. Host header authentication bypass via localhost
The application has admin routes that check the Host header instead of authentication tokens. The check is "is Host localhost or 127.0.0.1?" Many internal panels work this way.
If the reverse proxy forwards based on SNI (not Host), the request reaches the back-end with the localhost Host. The back-end skips authentication and renders the admin panel.
Variants to try if `localhost` is blocked:
The decimal `2130706433` and hex `0x7f000001` representations bypass naive string comparison.
4. Authentication bypass via X-Forwarded-For combined with Host
Some apps trust requests based on a combination of Host and source IP. Set both:
5. Duplicate Host header confusion
Send two Host headers. Some validators check the first; some apps use the last.
This is the ambiguous request variant. Front-end says "Host is anastech.com" (validates), back-end says "Host is attacker.com" (uses for URL).
6. Line folding (obsolete continuation)
RFC-7230 deprecated line folding, but old parsers still accept it.
The leading space on the second line continues the previous header. Some parsers concatenate, some take only the last token, some get confused. Worth one probe per target.
7. Absolute URI in the request line
HTTP/1.1 allows the request line to contain an absolute URI. The Host header is then supposed to match. Some parsers use the URI; some use the Host header.
When front-end uses URI and back-end uses Host (or vice versa), you have parser disagreement to exploit.
8. Web cache poisoning via ambiguous requests
Combine technique 5 or 2 with cache poisoning.
If the CDN does NOT include X-Forwarded-Host in the cache key but the application DOES reflect X-Forwarded-Host into the HTML, the poisoned response gets cached under the normal key. Every subsequent visitor for the cache TTL receives the malicious response.
Confirm by sending a second clean request (no X-Forwarded-Host) and checking that the response contains `attacker.com` and `X-Cache: HIT`.
9. Routing-based SSRF via Host header
Some proxies forward to whichever back-end the Host header names. You can reach internal services by setting Host to internal hostnames or IPs.
The fourth example reaches AWS cloud metadata. If the proxy forwards based on Host, you get back IAM credentials.
Cloud metadata Hosts to try:
- ●AWS ==> `169.254.169.254`
- ●Google Cloud ==> `metadata.google.internal` or `169.254.169.254`
- ●Azure ==> `169.254.169.254` (with header `Metadata: true`)
- ●Alibaba ==> `100.100.100.200`
- ●DigitalOcean ==> `169.254.169.254`
- ●Oracle ==> `192.0.0.192`
10. SSRF via flawed request parsing
The front-end parses the request line strictly. The back-end parses Host loosely. Inject `@` into the Host to fool one parser into thinking it is a user portion.
Some parsers split on `@` and use `internal-admin.local` as the actual host. Others take the whole string.
Variants:
11. Host validation bypass via connection state attack
This is the most subtle. The application validates the Host on the first request of a TCP connection but reuses connection state for subsequent requests on the same connection.
- ●Request 1 on a new TCP connection: `Host: anastech.com` (validates and authenticates).
- ●Request 2 on the same TCP connection: `Host: localhost` (no re-validation, attacker now has admin access).
Tools like Burp Repeater (with "Single connection" enabled) or raw socket scripts can chain these. Section 12 has a Python PoC.
12. Host header injection via the SNI
When TLS termination happens at the proxy, the SNI (Server Name Indication) is the hostname the client requested. Some applications read SNI as a trust signal. By controlling SNI separately from Host (using a tool like openssl s_client) you can desynchronize the two.
Front-end sees SNI=attacker.com, Host=anastech.com. Logic that combines them breaks.
13. Password reset poisoning via dangling markup
When the Host is inserted into HTML without escaping, you can inject markup that captures the rest of the page.
The email HTML becomes `<base href="x"><a href='//attacker.com/?...">`. The user clicks anything in the email and the URL goes to attacker.com.
Also works with `<img src='//attacker.com/?` to capture the page content via the Referer header.
14. Override headers stacking
When one override header is blocked, try multiple simultaneously.
Whichever the framework reads first wins.
15. Port confusion
Some applications validate the hostname but not the port. Inject a port that triggers different behavior.
The hostname check passes for `anastech.com`. The port `8080` or the trailing `.attacker.com` changes routing or URL generation.
16. Subdomain confusion
If the application allow-lists `*.anastech.com` (a wildcard), you can sometimes register a subdomain that the application accepts.
Some validators check "does Host end with anastech.com" but `anastech.com.evil.com` does not end with `anastech.com`. Reverse the check:
Some validators check "does Host start with allowed prefix". Both directions are worth probing.
17. CRLF injection via Host header
In rare cases, the Host header is concatenated into another header without sanitization. Try CRLF.
If the application uses the Host value to set a header (such as `Content-Location`), the CRLF can split the response and inject arbitrary headers.
18. Email header injection via Host
If the application sends an email with `From: noreply@<Host>`, you can inject `\r\n` into Host to inject email headers.
The email gets BCC'd to the attacker. Works in some PHP `mail()` setups.
19. Cache deception via Host case sensitivity
Some caches treat `ANASTECH.com` and `anastech.com` as different cache keys. Some applications normalize Host to lowercase before using. The desync lets you cache a logged-in user's response under a key the cache thinks is "public".
If the cache thinks `ANASTECH.com` is a different host (not yet in cache) and the back-end serves the page, the response (containing victim PII) gets cached. Any attacker requesting `ANASTECH.com` retrieves victim data.
20. Unicode Host
Some servers accept Punycode or IDN-encoded Host values. The display rendering and the validation can disagree.
Useful for phishing and for allow-list bypass when the validator uses string comparison after Unicode normalization but the URL builder does not normalize.
21. Trailing dot bypass
The trailing dot is valid DNS. Some allow-list checks fail because `anastech.com.` does not equal `anastech.com`. The back-end resolves the same site, but the URL generator includes the trailing dot.
22. Header smuggling via HTTP/2
In HTTP/2, the `:authority` pseudo-header replaces the Host header. Servers that downgrade HTTP/2 to HTTP/1.1 internally may pass `:authority` as `Host` to the back-end while a separate `Host` header (illegally) survives. The back-end ends up with two values.
Some HTTP/2 implementations forward both. The back-end sees the discrepancy and chooses one.
23. Web cache poisoning via custom override header
If the application uses an obscure header to determine its canonical hostname, the cache will not include that header in its key. Param Miner finds these. Examples seen in the wild:
24. Open redirect via Host header
Many redirect handlers build the redirect URL from Host.
The 302 response sends the user to `https://attacker.com/login`. Useful as a phishing primitive even when password reset poisoning is patched.
25. SAML / OAuth callback hijack via Host
Single Sign-On flows use absolute URLs (issuer, redirect_uri, ACS URL) constructed from Host. Poison the Host on the SAML AuthnRequest and the IdP sends the response to the attacker.
The IdP processes the request and POSTs the SAMLResponse to `https://attacker.com/sso/acs`. The attacker now has a valid SAML assertion for the victim.
26. Reset token leak via Referer
Even when the email link does NOT include the attacker domain (because the developer hardcoded `anastech.com`), an injected resource on the reset page can leak the token via the Referer header.
If you can poison the password reset PAGE (not the email link) by injecting an external resource:
The attacker reads `pixel.png` access logs and sees the token in the Referer.
27. Internal admin route discovery via Host
Internal admin routes are often named after Host-based virtual hosts. Try common admin hostnames.
If the proxy routes by Host, you may stumble onto internal sites.
28. Path-relative redirect with Host injection
Apps that build redirects like `Location: //{Host}/path` can be tricked.
Response:
The protocol-relative URL inherits the user's protocol but the host is fully attacker-controlled.
29. Cache key normalization desync
Cloudflare and other CDNs normalize cache keys (strip default ports, lowercase host). Applications often do not. If the app distinguishes `anastech.com` from `anastech.com:443` but the cache treats them as identical, you can poison the key for both.
30. Connection coalescing in HTTP/2
HTTP/2 allows the client (or in some cases an intermediary) to reuse the same TLS connection for multiple hostnames with the same certificate. A wildcard cert for `*.anastech.com` causes browsers and proxies to coalesce requests for `admin.anastech.com` and `public.anastech.com` over one connection. The Host header in HTTP/2 is the `:authority` field. A misconfigured back-end may route based on the connection's first authority while honoring subsequent `:authority` values, enabling cross-site Host poisoning over a single connection.
SECTION 12. Proof of Concept
Burp Suite step by step (basic password reset poisoning)
- ●1. Browse `anastech.com/forgot-password` and submit your test account's email.
- ●2. In Proxy ==> HTTP history, find the POST `/forgot-password` request.
- ●3. Right-click ==> Send to Repeater.
- ●4. Change `Host: anastech.com` to `Host: yourcollaborator.burpcollaborator.net`.
- ●5. Click Send.
- ●6. Open your test email account. The reset email contains a link pointing to your Collaborator domain.
- ●7. Click the link from a different browser to log the request. Read the Collaborator panel; you have captured the token.
- ●8. Visit `https://anastech.com/reset?token=<captured>` and set a new password.
Burp Suite step by step (web cache poisoning)
- ●1. Browse to the homepage. Capture the GET / request.
- ●2. Send to Repeater. Add `X-Forwarded-Host: attacker.com` (keep Host=anastech.com).
- ●3. Send. Look at the response for any reflection of `attacker.com`.
- ●4. If reflected, look at the response headers for `Cache-Control`, `X-Cache`, `Age`.
- ●5. Send the request a second time. If the response includes `X-Cache: HIT` AND still contains `attacker.com`, the cache is poisoned.
- ●6. Open a private browser window, visit `anastech.com`, and confirm the page loads attacker.com resources for every visitor.
Python PoC: end-to-end password reset poisoning capture
Python PoC: connection state Host bypass
Bash PoC: routing-based SSRF to AWS metadata
PowerShell PoC: header smuggling sweep
Node.js PoC: dangling markup injection
CSRF-chained admin delete via Host bypass
This is a chained exploit: Host bypass gives access to `/admin/delete`, and a forged CSRF token issued from the legitimate session allows the action.
Steps to build the chain:
- ●1. Confirm `Host: 192.168.0.1` (or `localhost`) gets you into `/admin/*` routes.
- ●2. From a low-privileged session, request `/admin/delete?username=carlos` to capture the CSRF form token. Most apps issue tokens to anyone who can render the page.
- ●3. Use that token in the POST body of the actual delete request.
- ●4. Send the POST with `Host: 192.168.0.1`, your session cookie, the captured CSRF token, and the target username.
- ●5. Carlos's account is deleted.
The Content-Length must be correct for the body length. With Burp, "Update Content-Length" handles this automatically. Sinon t9dr tbdllha nta ela hassab kolla chars wla espace b 1.
Burp tip for every Host header test
- ●1. In Repeater, switch the protocol from HTTP/2 to HTTP/1.1 (Inspector ==> Request attributes ==> Protocol). Host editing is cleaner in HTTP/1.1.
- ●2. When testing override headers, KEEP `Host: anastech.com` and ADD the override below. Many validators fail open when only the override exists.
- ●3. Enable "Show non-printables" so you can spot trailing whitespace, line folding, and CRLF injection.
- ●4. For connection-state attacks, use "Single connection" in Repeater (Repeater menu ==> Single connection).
- ●5. For caching tests, send each request twice within the cache TTL (`Cache-Control: max-age=N`). Compare the `X-Cache` and `Age` headers between the two responses.
- ●6. For Collaborator (or interact.sh), insert your subdomain in BOTH `Host` and `X-Forwarded-Host` to maximize chance of hitting the right code path.
SECTION 13. Payloads
Payloads grouped by goal. Use them as a tester library; mix and match.
Tier 1: Basic detection probes
Tier 2: Override headers
Tier 3: Duplicate and ambiguous
Tier 4: Absolute URI in request line
Tier 5: Localhost bypasses
Tier 6: Cloud metadata
Tier 7: SSRF parsing tricks
Tier 8: Dangling markup (HTML injection via Host)
Tier 9: Email header injection via Host
Tier 10: CRLF injection via Host (rare)
Tier 11: Unicode and punycode
Tier 12: Path-relative chain payloads
WAF bypass tweaks
- ●Mix case: `host: attacker.com` (lowercase), `HOST: attacker.com` (uppercase).
- ●Add trailing whitespace: `Host: attacker.com `.
- ●Use tab characters: `Host:<tab>attacker.com`.
- ●Combine duplicate Host with override headers to confuse WAF parsers.
- ●Send Host in HTTP/2 as `:authority` and add `host` as a regular header to confuse downgrade proxies.
SECTION 14. Wordlists and Payload Libraries
Public wordlists and reference repos
- ●PayloadsAllTheThings - Host Header Injection ==> https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Host%20Header%20Injection
- ●HackTricks - Host header injection ==> https://book.hacktricks.xyz/pentesting-web/abusing-hop-by-hop-headers
- ●HackTricks - Cache Poisoning to DoS / RCE ==> https://book.hacktricks.xyz/pentesting-web/cache-deception
- ●OWASP Web Security Testing Guide - Testing for Host Header Injection ==> https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/17-Testing_for_Host_Header_Injection
- ●SecLists - Host header wordlist ==> https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/burp-parameter-names.txt
- ●Param Miner header word file ==> bundled with the Burp Param Miner extension's resources directory
- ●SSRF cheat sheet (Cloud metadata Hosts) ==> https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Request%20Forgery
- ●Anas Magane Pentesting Notes - Host Header ==> https://github.com/Anas-Magane/Pentesting/tree/main/TOP_10_OWASP/HOST_HEADER
Complete HTTP header reference (for fuzzing and override testing)
Use this as a working list. Inject your Host marker into each one to discover undocumented overrides.
Request headers
Response headers (useful for cache and security indicators)
Tracing and routing headers (the gold mine for Host overrides)
Fuzz every one of these with `attacker.com` as the value and watch for reflection or routing change. The more obscure the header, the less likely the cache or WAF normalizes it, the higher the chance of a clean cache-poisoning primitive.
SECTION 15. Impact
The impact of HTTP Host header attacks ranges from open redirect to full cloud account takeover. Severity escalates from low to critical:
- ●1. Open redirect. The attacker tricks users into clicking links that appear to come from anastech.com but land on attacker.com. Used as a phishing primitive.
- ●2. Reflected XSS via Host. When Host is inserted into HTML without escaping, the attacker injects script. Combine with cache poisoning for stored XSS impact.
- ●3. Password reset poisoning. The attacker hijacks any user's password reset token. Account takeover per victim. Bounty range: $500-$5,000.
- ●4. Account verification poisoning. Same as password reset but for new account confirmation links, magic-login emails, billing receipts, invitation tokens. Each side channel is its own attack surface.
- ●5. Web cache poisoning. The attacker poisons the CDN cache for the entire user base for the cache TTL. Mass exploitation. Bounty range: $1,000-$20,000.
- ●6. Authentication bypass via localhost. Direct admin panel access without credentials. Bounty range: $2,000-$15,000.
- ●7. Routing-based SSRF. The attacker reaches internal services not exposed to the internet, including admin panels and metadata services.
- ●8. Cloud metadata access. AWS, GCP, Azure metadata service exposed via Host=169.254.169.254. The attacker reads IAM credentials, takes over the entire cloud account. Bounty range: $5,000-$50,000.
- ●9. SAML / OAuth callback hijack. The IdP sends the SAMLResponse or OAuth code to attacker.com. The attacker authenticates as the victim. Bounty range: $5,000-$30,000.
- ●10. Mass account takeover via cache-poisoned reset link. Combine cache poisoning with the reset page. Every user who clicks the cached link leaks their token. The most devastating chain.
- ●11. CSRF protection bypass. When the application allows admin routes from `Host: localhost`, the attacker can perform any admin action by forging the appropriate request.
- ●12. Reputational damage and regulatory exposure. PCI-DSS, GDPR, HIPAA, SOC 2 all treat unauthorized data access from this vector as a reportable breach.
Real-world cost: a publicly disclosed Host header bug at a fintech in 2024 led to a $4.2M regulatory fine because customer PII was exposed via cache poisoning. The technical bug was a single line of code.
SECTION 16. Prevention
Vulnerable code vs Secure code
VULNERABLE (Python Flask):
SECURE (Python Flask):
The fix explained
- ●The vulnerable version reads the request's Host header. The Host header is attacker-controlled. The fix is to read the URL from a configuration file that is set by the deployment process, not by the user.
- ●If the configuration must adapt to multiple environments (dev/staging/prod), use environment variables, not request headers. Set them at deploy time.
- ●Validate any Host that does reach the application against an allow-list of known good hostnames. Reject all others with HTTP 400.
Eight prevention rules
- ●1. Never use the Host header to build user-facing URLs. Use a hardcoded base URL from config.
- ●2. Validate the Host header against an allow-list at the framework level. Django uses `ALLOWED_HOSTS`. Set it explicitly; do not use `*`.
- ●3. Configure the reverse proxy to enforce Host validation. NGINX `server_name`, Apache `ServerName`, Caddy `match` rules. Set the default vhost to return 421.
- ●4. Disable `X-Forwarded-Host` and similar override headers at the WAF or proxy layer unless explicitly required. Most apps do not need them.
- ●5. Use the `Vary: X-Forwarded-Host` header if you must trust override headers, so caches separate poisoned responses.
- ●6. Set a strict CSP with `default-src 'self'` so injected attacker.com scripts cannot execute even if reflected.
- ●7. Hash and bind reset tokens to the email address so even a leaked token cannot be reused against a different account.
- ●8. Log and alert on requests with unexpected Host values. Any Host outside the allow-list is suspicious; a request with `Host: localhost` from an external IP is a clear attack.
Developer checklist
- ●[ ] No `request.host`, `request.headers.host`, `req.hostname`, `Request.Host`, `$_SERVER["HTTP_HOST"]`, `HttpServletRequest.getHeader("Host")`, `ServletUriComponentsBuilder.fromCurrentContextPath()` in any code that builds emails, redirects, or absolute URLs.
- ●[ ] Canonical base URL is set in config and loaded once at startup.
- ●[ ] `ALLOWED_HOSTS` (Django) / equivalent host validation is set with explicit hostnames, no wildcards.
- ●[ ] X-Forwarded-Host is either ignored or validated against the same allow-list.
- ●[ ] Reverse proxy has a default vhost that returns 421 (Misdirected Request) for unknown Hosts.
- ●[ ] Password reset tokens are short-lived (5-15 minutes) and one-time-use.
- ●[ ] Password reset tokens are bound to the user's email; the reset endpoint re-checks the email.
- ●[ ] Caching layer includes Host in the cache key OR the application never reflects request headers in cached responses.
- ●[ ] Security tests include Host header probes for every authenticated route and every email-generating route.
- ●[ ] Logs capture the full Host header value for every request; alerts fire on values outside the allow-list.
Framework-specific secure examples
Django (production-grade)
Express (Node.js)
Spring Boot (Java)
NGINX configuration
Enterprise-level mitigations
- ●Deploy a central allow-list of known good Hosts at the edge (CDN, WAF) and reject everything else.
- ●Use canonical hostnames signed in JWT issuer / audience claims so even leaked tokens cannot be replayed against impersonated hosts.
- ●Tag every URL-generating function in the codebase with a static analysis lint rule that bans the use of `request.host`.
- ●Schedule quarterly red team exercises that specifically test Host header attacks across all customer-facing email and notification flows.
- ●Subscribe to your framework's security advisories: Django, Spring, Express, ASP.NET, Rails, Laravel.
- ●For multi-tenant SaaS, separate tenant Host resolution from URL generation entirely. Use opaque tenant IDs in URLs, not hostnames.
- ●Implement Host header diff alerts: monitor whether the Host header observed at the application differs from the Host implied by SNI; investigate any discrepancy.
SECTION 17. Real-World Cases
CVEs (2022-2026)
- ●CVE-2025-52560 (Kanboard, CWE-640) ==> Password reset emails derived from unvalidated Host header when `application_url` is unset. Patched October 2025.
- ●CVE-2024-46452 (CVSS 6.1) ==> Host Header Injection in the password reset function of a popular open-source online shop application. Disclosed 2024. The fix introduced a canonical URL config.
- ●CVE-2024-40686 (CVSS 7.5) ==> IBM SmartCloud Analytics Host Header Injection enabling cache poisoning and session hijacking. Patched in 2024.
- ●CVE-2024-21733 (Apache Tomcat, partial overlap) ==> Browser-powered client-side desync that also enables Host header desync between front-end and back-end.
- ●CVE-2023-32314 (vm2 sandbox) ==> Host-based path detection bypass leading to sandbox escape.
- ●CVE-2023-42795 (Apache Tomcat) ==> Incomplete recycling of HTTP/2 connections; Host header from prior request leaked into next request on the same connection.
- ●CVE-2022-2812 (Authelia) ==> Host header bypass allowed redirect to attacker-controlled domain after authentication, leading to OAuth token theft.
- ●CVE-2022-21703 (Grafana) ==> Cross-origin request forgery via Host header injection in Grafana's password reset endpoint.
- ●CVE-2022-31090 (Apache HttpComponents Client) ==> Improper validation of authentication challenge based on Host header allowed credential leak.
- ●CVE-2021-44531 (Node.js) ==> The Subject Alternative Names section of certificates is checked against Host; bypass via embedded null bytes.
HackerOne disclosures (with bounty amounts where known)
- ●TheIndianNetwork - $1,000 ==> Host Header Injection on a major SaaS platform leading to account takeover via password reset poisoning. Reported 2025. The author submitted a Burp Repeater PoC and got the bounty within 24 hours.
- ●HackerOne report 1679969 - US Dept of Defense ==> Host Header Injection across multiple .mil subdomains, cache poisoning chain. Acknowledged 2023.
- ●HackerOne report 1783015 - Urban Company ==> Host header injection chained with SSRF. The Host=internal-admin reachable from public proxy. Acknowledged.
- ●HackerOne report 1098948 - Kartpay ==> Host Header Injection on main domain via X-Forwarded-Host. Closed as Resolved with bounty.
- ●HackerOne report 1392935 - Omise - $200 ==> XSS via X-Forwarded-Host header. Stored XSS chain. Resolved December 2021.
- ●HackerOne report 698416 - New Relic ==> Host Header Injection in account-related emails. Disclosed.
- ●HackerOne report 226659 ==> Password Reset link hijacking via Host Header Poisoning. The classic report that put this bug class on every hunter's radar.
- ●HackerOne report 170333 - RubyGems ==> Host Header Injection / Redirection. The RubyGems team disclosed the report after patching.
- ●Pethuraj blog - $800 ==> Host Header Injection on a SaaS provider's marketing domain. Reflected Host in canonical link, escalated to phishing primitive.
- ●Multiple programs - $100-$500 range ==> Reflected Host header bugs without full impact chain. Common quick wins for new bounty hunters.
Notable historical milestones
- ●2008 ==> Original "Host Header Injection: Reset Password Poisoning" research by Skeletonscribe documented the password reset chain. The technique was named.
- ●2013 ==> James Kettle published the first wide-scope research showing the bug affected major sites (Gmail, GitHub, Joomla, Drupal at the time). Most patched within weeks.
- ●2018 ==> Web cache poisoning via Host headers became a mainstream technique after Kettle's "Practical Web Cache Poisoning" paper. Multiple six-figure bug bounty disclosures followed.
- ●2020 ==> Routing-based SSRF via Host became a top SSRF primitive after the Capital One breach exposed how cloud metadata exposure compounds with these bugs.
- ●2022 ==> Connection-state Host attacks introduced in "Browser-Powered Desync Attacks" research; new class of authentication bypasses.
- ●2024-2025 ==> Continued CVE flow shows the bug is not dying. Modern variants combine Host with HTTP/2 :authority and CDN cache normalization quirks.
Lessons learned
- ●The bug is twenty years old and still ships in 2025. Every framework patches it; every new application reintroduces it.
- ●The convenient way to build URLs is the wrong way. Hardcode the canonical base URL, always.
- ●Password reset flows are the highest-impact location. Every bug bounty hunter should test them first.
- ●Cache poisoning amplifies a single Host header bug from "one victim" to "thousands of victims" instantly.
- ●Cloud metadata exposure (169.254.169.254) is a $50k+ bounty chain on most modern bug bounty programs. Always test it.
- ●X-Forwarded-Host is the single most common override. If Host is patched, try X-Forwarded-Host.
SECTION 18. References
- ●OWASP - Testing for Host Header Injection ==> https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/17-Testing_for_Host_Header_Injection
- ●OWASP - Host Header Attack ==> https://owasp.org/www-community/attacks/Cache_Poisoning
- ●CWE-20: Improper Input Validation ==> https://cwe.mitre.org/data/definitions/20.html
- ●CWE-640: Weak Password Recovery Mechanism for Forgotten Password ==> https://cwe.mitre.org/data/definitions/640.html
- ●CWE-444: Inconsistent Interpretation of HTTP Requests ==> https://cwe.mitre.org/data/definitions/444.html
- ●CWE-918: Server-Side Request Forgery (SSRF) ==> https://cwe.mitre.org/data/definitions/918.html
- ●CWE-345: Insufficient Verification of Data Authenticity ==> https://cwe.mitre.org/data/definitions/345.html
- ●HackTricks - Host Header Injection ==> https://book.hacktricks.xyz/pentesting-web/abusing-hop-by-hop-headers
- ●HackTricks - Cache Deception ==> https://book.hacktricks.xyz/pentesting-web/cache-deception
- ●PayloadsAllTheThings - Host Header Injection ==> https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Host%20Header%20Injection
- ●RFC 9110 (HTTP Semantics) - Host header definition ==> https://www.rfc-editor.org/rfc/rfc9110#section-7.2
- ●RFC 7239 (Forwarded HTTP Extension) ==> https://www.rfc-editor.org/rfc/rfc7239
- ●RFC 9113 (HTTP/2) - :authority pseudo-header ==> https://www.rfc-editor.org/rfc/rfc9113
- ●Acunetix - Host Header Attack ==> https://www.acunetix.com/vulnerabilities/web/host-header-attack/
- ●Invicti - Password Reset Poisoning ==> https://www.invicti.com/learn/password-reset-poisoning
- ●Anas Magane Pentesting Notes ==> https://github.com/Anas-Magane/Pentesting/tree/main/TOP_10_OWASP/HOST_HEADER
- ●Skeletonscribe original research - Password Reset Poisoning (historical) ==> http://www.skeletonscribe.net/2013/05/practical-http-host-header-attacks.html
- ●Reddelexc HackerOne Reports - Host Header ==> https://github.com/reddelexc/hackerone-reports/blob/master/tops_by_bug_type/TOPHOSTHEADER.md
SECTION 19. Practical Labs
SOON.
SECTION 20. Cheat Sheet
SECTION 21. Exam
The exam has 30 multiple-choice questions. The platform picks 20 random questions per attempt. Score 16/20 to pass. Score 14-15 to retry. Score 0-13 to fail and review the course.
Q1. The Host header is mandatory in which HTTP version? A. HTTP/0.9 B. HTTP/1.0 C. HTTP/1.1 D. HTTP/3 only Answer: C.
Q2. A server uses one IP to serve multiple websites. The mechanism that lets the server know which site you want is called: A. Reverse DNS B. Virtual hosting via the Host header C. SNI only D. TCP source port routing Answer: B.
Q3. Password reset poisoning via Host header works because: A. The Host header is encrypted by TLS so it cannot be modified B. The application builds the reset link using the Host header value C. The Host header is signed by the server D. The reset token is stored in the Host header Answer: B.
Q4. Which header is the most common alternative to Host that overrides the Host value at the application layer? A. X-Forwarded-Proto B. X-Forwarded-For C. X-Forwarded-Host D. X-Real-IP Answer: C.
Q5. The primary CWE associated with weak password recovery via Host header poisoning is: A. CWE-79 B. CWE-89 C. CWE-640 D. CWE-22 Answer: C.
Q6. Setting `Host: localhost` on a request to `/admin` may bypass authentication when: A. The browser refuses to send the request B. The application skips auth checks for localhost-based Hosts and the proxy forwards Host as-is C. The DNS resolves localhost to a public IP D. The CDN encrypts the Host header Answer: B.
Q7. Which of the following is NOT typically a Host override header? A. X-Forwarded-Host B. X-Host C. X-Forwarded-Server D. X-Powered-By Answer: D.
Q8. The X-Cache header value `HIT` means: A. The response was served from the origin server B. The response was served from the cache C. The request was rejected D. The response was hashed Answer: B.
Q9. Web cache poisoning via Host header works best when: A. The cache includes the Host header in the cache key B. The cache does NOT include the override header in the key but the application reflects it C. Caching is disabled D. The application uses HTTPS Answer: B.
Q10. AWS cloud metadata is reachable at which IP? A. 10.0.0.1 B. 192.168.1.1 C. 169.254.169.254 D. 127.0.0.1 Answer: C.
Q11. Routing-based SSRF via Host header allows the attacker to: A. Encrypt the response B. Reach internal services not exposed to the internet by setting Host to internal hostnames C. Generate a TLS certificate D. Bypass DNS Answer: B.
Q12. Duplicate Host headers can cause vulnerabilities when: A. The browser refuses both B. The front-end parses one Host and the back-end parses the other C. They are encrypted D. They are stripped by TLS Answer: B.
Q13. The connection state Host attack works because: A. The application validates Host only on the first request of a TCP connection B. TLS prevents Host changes C. The browser caches Host D. The Host header is server-generated Answer: A.
Q14. A canonical defense for Host header attacks is: A. Read the Host header in production but not staging B. Hardcode the canonical base URL in config and never use the Host header to build URLs C. Always trust X-Forwarded-Host D. Disable HTTPS Answer: B.
Q15. In Django, the configuration setting that allow-lists valid Hosts is: A. INSTALLED_APPS B. ALLOWED_HOSTS C. MIDDLEWARE D. DATABASES Answer: B.
Q16. In Express (Node.js), trusting X-Forwarded-Host is controlled by: A. trust proxy setting B. JSON parser C. CORS module D. compression module Answer: A.
Q17. A request with `Host: 169.254.169.254` is most commonly used to: A. Test browser compatibility B. Reach cloud instance metadata service C. Bypass HTTPS D. Modify TCP port Answer: B.
Q18. Password reset tokens should be: A. Long-lived, multi-use, shared across users B. Short-lived, one-time use, bound to the email and account C. Stored in the Host header D. Sent over HTTP Answer: B.
Q19. Which of these is a localhost bypass payload? A. Host: 2130706433 B. Host: google.com C. Host: ::ffff:8.8.8.8 D. Host: 0.0.255.0 Answer: A.
Q20. The Forwarded header (RFC 7239) syntax for Host is: A. Forwarded: by=... B. Forwarded: for=... C. Forwarded: host=... D. Forwarded: proto=... Answer: C.
Q21. Dangling markup via Host header injection happens when: A. The Host is encoded as JSON B. The Host value is inserted into HTML without HTML-escaping C. The Host header is compressed D. The Host is signed with HMAC Answer: B.
Q22. The `:authority` pseudo-header in HTTP/2 replaces: A. Method B. Path C. Host header D. User-Agent Answer: C.
Q23. Which HTTP response code is a sensible default for unknown Host values? A. 200 OK B. 301 Moved Permanently C. 421 Misdirected Request D. 503 Service Unavailable Answer: C.
Q24. A trailing dot in Host (e.g., `anastech.com.`) can: A. Cause the request to fail TLS B. Bypass allow-list checks that compare strings exactly C. Reverse DNS poisoning D. Trigger a Content-Length mismatch Answer: B.
Q25. Burp Param Miner is most useful for: A. SQL injection B. Discovering undocumented override headers C. Generating TLS certs D. Compressing requests Answer: B.
Q26. The `Vary` header in HTTP responses is relevant to Host header attacks because: A. It prevents TLS downgrade B. It tells caches which request headers affect the response, so caches separate keys accordingly C. It encrypts the body D. It signs the Host header Answer: B.
Q27. Routing-based SSRF via Host header has been used to: A. Disable JavaScript B. Read AWS IAM credentials from the metadata service C. Spoof TLS certificates D. Generate QR codes Answer: B.
Q28. A SAML callback hijack via Host header poisoning succeeds because: A. SAML is not cryptographic B. The IdP builds the ACS (Assertion Consumer Service) URL from Host or from a request-controlled value C. The browser refuses SAML over HTTPS D. CORS prevents the redirect Answer: B.
Q29. Which combination most commonly enables MASS exploitation via Host header bug? A. Host + sticky session B. Host + cache poisoning C. Host + reverse DNS D. Host + HSTS Answer: B.
Q30. The fix for a Host header bug is: A. Add logging B. Use a hardcoded canonical URL from config; never use Host to build URLs C. Trust X-Forwarded-Host instead D. Disable HTTP/2 Answer: B.
Scoring guide
- ●27-30 correct ==> Excellent. You understand the entire bug class and its variants.
- ●24-26 correct ==> Solid. Practice on a live bug bounty target.
- ●20-23 correct ==> Pass with reservation. Review Sections 11 and 16.
- ●16-19 correct ==> Pass at the minimum threshold. Review the whole course.
- ●14-15 correct ==> Retry. Read Sections 2, 8, and 11 again.
- ●0-13 correct ==> Fail. Restart the course from Section 1.
SECTION 22. Certificate Requirements
To earn the ANAS EDUCATION HTTP Host Header Attacks certificate:
- ●Complete all 24 sections (read or watch each).
- ●Complete all ANAS EDUCATION Host header attack labs (released as SOON).
- ●Pass the final exam with at least 16/20.
SECTION 23. Important Notes
Common Beginner Mistakes
- ●Testing only the `Host` header. The bounty is usually in `X-Forwarded-Host`. Always test the override headers separately.
- ●Forgetting to keep `Host: anastech.com` when testing overrides. Many WAFs reject requests where Host alone is changed; the override headers slip through.
- ●Concluding "no bug" because the response does not contain `attacker.com`. The bug often manifests in side effects: email links, cached responses, redirects on the NEXT request.
- ●Not testing connection state. Burp's default is to create a new connection per request, which hides connection-state Host bypass bugs.
- ●Reporting reflected Host without escalation. A "Host appears in response body" finding alone is informational; build the full chain (password reset, cache, SSRF) for real impact.
Pentester Tips
- ●Always test password reset, account verification, and email invitation flows first.
- ●Use Burp Collaborator (or interact.sh) so you get DNS and HTTP callbacks confirming the bug worked.
- ●When testing the forgot-password endpoint, use your own test account so you receive the resulting email and can capture the exact link.
- ●Use Param Miner to discover non-standard override headers. Many enterprises use custom names.
- ●For cache poisoning testing, always send a clean second request and check `X-Cache: HIT` plus reflection.
- ●When checking `localhost` bypass, also try IPv6 (`[::1]`), decimal (`2130706433`), and trailing dot (`localhost.`).
Bug Bounty Tips
- ●A clean, reproducible password reset poisoning PoC typically pays $1,000-$5,000 on mid-tier programs and $5,000-$20,000 on top-tier programs.
- ●Web cache poisoning chains with Host pay 5-10x more than the same bug without cache poisoning.
- ●Routing-based SSRF chains to cloud metadata pay $10,000+ on most cloud-focused bounty programs.
- ●Write your reports with three sections: the vulnerable request, the resulting impact (email, cache, etc.), and a one-paragraph mitigation. Programs reward clarity.
- ●Include a 30-second video demo when possible; triagers love video and triage faster.
- ●When the bug is in a less obvious feature (account verification rather than password reset), call this out explicitly. Triagers may otherwise close as duplicate of a known reset-poisoning report.
Red Team Notes
- ●In a red team engagement, the Host header attack is a quiet primitive. It does not trigger WAF rules typically focused on path or body content.
- ●Combine Host header attacks with phishing for high-fidelity account takeover (poison the reset, then trigger it via a target spear-phish).
- ●Cache poisoning in a red team enables a fast, targeted attack that disappears after the cache TTL, leaving little forensic trail.
- ●Routing-based Host SSRF often gives the same level of access as VPN access but without triggering VPN monitoring or NDR alerts.
- ●Use HTTP/2 `:authority` desync against modern targets; many SOCs do not yet monitor for this variant.
Real-World Advice
- ●The bug lives in the smallest part of code: one line that reads `request.host`. Patches are short. The hard part is finding every place that reads it.
- ●Static analysis tools usually do NOT flag Host header usage by default. You have to add custom lint rules.
- ●Pen tests focused only on the OWASP Top 10 often miss Host header attacks because they are split across CWE-20, CWE-640, CWE-918, CWE-444. Make sure your scope explicitly includes them.
Things to Remember During Exams
- ●Host header overrides include both Host and X-Forwarded-Host (and others). Know the top 5 by heart.
- ●The X-Cache header tells you HIT (cache) or MISS (origin). HIT plus reflection equals poisoning confirmed.
- ●Localhost variants: `127.0.0.1`, `localhost`, `[::1]`, `2130706433`, `127.0.0.1.`, `0x7f000001`.
- ●The fix is always: hardcode canonical URL, allow-list validate Host, never use Host to build URLs.
- ●CWE-640 is the primary CWE for password reset poisoning.
Things to Remember During Real Assessments
- ●Test every email-generating feature, not just password reset. Verification emails, billing emails, invitations are all in scope.
- ●Test override headers individually AND in combinations.
- ●Check authenticated routes for localhost-bypass behavior.
- ●Test routing-based SSRF with cloud metadata IPs even if the application looks unrelated to cloud. Many internal services are reachable.
- ●Always verify cache behavior with a second clean request before declaring "cache poisoned".
Frequently Confused Concepts
- ●Host vs SNI ==> Host is in the HTTP header (application layer). SNI is in the TLS ClientHello (transport layer). The two can disagree. A proxy may route by SNI but the application reads Host.
- ●Host vs :authority ==> In HTTP/1.1 the Host header carries the hostname; in HTTP/2 the `:authority` pseudo-header does. Both can coexist during HTTP/2 downgrade and confuse parsers.
- ●Host header injection vs CRLF injection ==> Host header injection bends an existing header value to attacker.com. CRLF injection injects entirely new headers via `\r\n`. They sometimes chain.
- ●Cache poisoning vs cache deception ==> Poisoning makes the cache return malicious content to victims. Deception makes the cache store private content under a public key. Host bugs enable both.
- ●Password reset poisoning vs open redirect ==> Open redirect bounces a victim to attacker.com after they click. Reset poisoning gives the attacker the secret token directly. Reset poisoning is higher severity.
Interview Tips
- ●Be ready to explain why the Host header is attacker-controlled. The answer: "Anyone with a TCP socket can send any value; the browser is one client among many."
- ●Be ready to describe the password reset poisoning chain end-to-end in two minutes.
- ●Be ready to name 5 override headers without looking them up.
- ●Know the fix: hardcoded canonical URL plus allow-list validation.
- ●Know one real CVE from the last 24 months (CVE-2024-46452 is a good answer).
Key Takeaways
- ●The Host header is application-layer attacker input, no different from a query parameter.
- ●Any use of the Host header to build URLs, route traffic, or authorize requests creates a potential vulnerability.
- ●Password reset poisoning is the highest-impact single-victim attack; web cache poisoning is the highest-impact multi-victim attack.
- ●Always test override headers (X-Forwarded-Host first) when the basic Host is patched.
- ●The fix is small (hardcode canonical URL) but the discipline must be company-wide.
SECTION 24. Final Word from Your Instructor
The HTTP Host header is the most ignored attack surface in modern web applications.
Every developer learns about SQL injection. Every developer learns about XSS. Few developers learn that the Host header on every incoming request is attacker-controllable text. The Host header arrives looking official, parsed by the framework, exposed as `request.host`. It feels safe.
It is not safe. It is the most untrusted byte in the entire HTTP request.
Every time a developer writes:
A new password reset poisoning bug is born somewhere in the world.
Every time a developer writes:
A new cache poisoning vector is born.
Every time a proxy admin writes:
A new routing-based SSRF is born.
Your job, as a hunter, is to look at any web application and ask one question: "Does this app read the Host header to make a decision?"
When you see a password reset feature, ask: "Where does the link in the email come from?"
When you see a redirect, ask: "Is the Location header built from Host?"
When you see an admin route, ask: "Is there a check like 'if Host equals localhost, skip auth'?"
When you see a SAML or OAuth callback URL, ask: "Is the ACS or redirect_uri derived from Host?"
When you see a CDN-fronted site, ask: "What headers does the cache include in its key? And what headers does the app reflect into the cached HTML?"
When you see an HTTP/2 request, ask: "Does the back-end still read a Host header even though :authority is the canonical one?"
If the answer to any of these is "yes, without validation", you have found a bug worth thousands of dollars.
The password reset poisoning chain is the clearest demonstration. Memorize it.
The X-Forwarded-Host override is the most common bypass when the basic Host is patched. Memorize it.
The connection-state attack is the most subtle, the highest-paying when found. Memorize it.
The routing-based SSRF chain to cloud metadata is the most lucrative. Memorize it.
The bug class is twenty years old and still ships in 2026. You will find it on production sites you visit every day. You will find it on bug bounty programs that have been running for ten years. You will find it on internal pen tests. You will find it on your own employer's apps.
Bring a list of the override headers from Section 14. Bring the cheat sheet from Section 20. Bring patience to test every email-generating feature you find.
- ●Welcome to the world where one wrong header changes everything.
- ●Go hunt.