oss-sec mailing list archives
Host ambiguous requests through NGINX $host and Debian's proxy_params
From: gabriel.corona () free fr
Date: Thu, 21 May 2026 13:59:20 +0200
When receiving a HTTP/1.x request, NGINX does not check that the authority coming from the request line (if present) is consistent with the authority from the Host header field. In some deployments (when $http_host is used)
an attacker could exploit this ambiguity to bypass security restrictions configured in NGINX (of have other security impacts). Example: GET http://foo/ HTTP/1.1 <- Used for virtual host routing User-Agent: UA Host: bar <- Used for $http_host Debian's proxy_param file used to use $http_host: proxy_set_header Host $http_host; This has been fixed as part of Debian bug #1126960 [1]. In this case, "foo" is used for virtual host routing but the request is forwarded as: GET / HTTP/1.1 User-Agent: UA Host: bar X-Real-IP: ... X-Forwarded-For: ... X-Forwarded-Proto: ... If the backend application actually makes use of the Host value, this might have a security impact. For example, * if the backend application uses the Host value for tenant dispatching;* and NGINX is configured with per-tenant configuration (eg. authorization,
logging, etc),
then this might have a security impact.
Example NGINX configuration:
server {
listen 443 ssl;
server_name tenant1;
ssl_certificate /etc/nginx/ssl/tenant1.crt;
ssl_certificate_key /etc/nginx/ssl/tenant1.key;
location / {
proxy_pass http://backend;
include proxy_params;
}
}
server {
listen 443 ssl;
server_name host2;
ssl_certificate /etc/nginx/ssl/tenant2.crt;
ssl_certificate_key /etc/nginx/ssl/tenant2.key;
location / {
allow 10.0.0.0/8;
allow 192.168.0.0/16;
allow 127.0.0.1/8;
deny all;
proxy_pass http://backend;
include proxy_params;
}
}
In this example, tenant2 is expected to be only available from
private IP addresses. However, an attacker could target tenant2
with:
GET http://tenant1/ HTTP/1.1 <- Used for virtual host routing
User-Agent: UA
Host: tenant2 <- Used for $http_host
Another potential application, would be to send access logs
of an attack to the log files of the wrong tenant.
You might be impacted if:
* NGINX is directly exposed;
* you use $http_host (eg. through Debian's proxy_params).
NGINX's position
----------------
NGINX's position is that the bug is to use $http host. NGINX's
documentation recommends using $host [2]:
proxy_set_header Host $host;
I would claim that NGINX could (should?):
1. either reject host ambiguous requests altogether
(because they are attacks right?);
2. or override the HTTP header with the value from the request line.
These behaviors are consistent with what other (open-soruce)
HTTP server do:
1. NGINX when using HTTP/2, HA proxy for solution 1;
2. Traefik, Caddy, Apache HTTPD for solution 2.
At the very least, the security impact of using $host vs
$http_host should be better documented.
Mitigations
-----------
Mitigation 1: always use `$host` instead of `$http_host`:
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Host $host;
Mitigation 1b: always use `$server_name` instead of `$http_host`:
proxy_set_header Host $server_name;
proxy_set_header X-Forwarded-Host $server_name;
Mitigation 1c: always the hardcoded expected hostname instead of
`$http_host`.
proxy_set_header Host "www.example.com"; proxy_set_header X-Forwarded-Host "www.example.com";Mitigation 2: use NGINX directive to reject ambiguous (malicious) requests.
# Does not work when using ports:
if ($host != $http_host) {
return 421 "Ambiguous host";
}
# Since nginx 1.29.3:
if ($http_host != "$host$is_request_port$request_port") {
return 421 "Ambiguous host";
}
Debian info
-----------
Snippet from Debian changelogs:
nginx (1.26.3-3+deb13u4) trixie; urgency=medium
* d/conf/*_params: use "$host" instead of "$http_host"
* "$http_host" forwards the Host header exactly as supplied by
the client
and may not match the effective request target (e.g.
absolute-form
requests with a conflicting Host header)this can expose inconsistent or attacker-controlled host values to
backend applications (uwsgi, fastcgi, scgi, proxy) * switch to "$host" as a safer, normalized alternative * note: this changes behaviour, as "$host" does not preserve theclient-supplied port; deployments relying on "$http_host" including
a port number may be affected* it is workaround for Debian bug #1126960 for stable/oldstable release
-- Jan Mojžíš <janmojzis () debian org> Mon, 20 Apr 2026 17:52:06 +0000
New proxy_params file: # !!! Security workaround !!! # Do not set the `Host` header as "$http_host". # # "$http_host" is the Host header exactly as supplied by the client.# This is unsafe when a client sends an absolute-form request target together
# with a different Host header, for example: # # GET https://example.com/ HTTP/1.1 # Host: malformedhost ## In such a case, passing "$http_host" upstream exposes the raw client-supplied # Host value ("malformedhost") to the backend application, even though it does # not match the effective request target. Applications often use HTTP_HOST for # redirects, absolute URL generation, virtual host routing, or security checks; # forwarding the raw Host header can therefore lead to incorrect or unsafe
# behaviour. ## Newer nginx versions (since 1.30.0) introduce variables "$is_request_port" and
# "$request_port", allowing `Host` to be constructed as: # $host$is_request_port$request_port ## In stable/oldstable packages we use "$host" as a security workaround.
# It avoids forwarding an untrusted raw Host header to the backend. ## Note: this changes behaviour compared to previous versions, because "$host" # does not preserve the client-supplied port, while "$http_host" typically # does. Existing deployments that rely on "$http_host" containing a port number
# may therefore break or behave differently after this change. proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; [1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1126960 [2] https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/[3] https://metadata.ftp-master.debian.org/changelogs//main/n/nginx/nginx_1.26.3-3+deb13u5_changelog
Regard, -- Gabriel Corona
Current thread:
- Host ambiguous requests through NGINX $host and Debian's proxy_params gabriel . corona (May 21)
