[Pkg-nginx-maintainers] Bug#1126960: Bug#1126960: Bug#1126960: nginx: proxy_params should use $host instead of $http_host
Jérémy Lal
kapouer at melix.org
Thu Mar 5 14:30:38 GMT 2026
Le ven. 27 févr. 2026 à 10:13, Jérémy Lal <kapouer at melix.org> a écrit :
>
>
> Le ven. 27 févr. 2026 à 09:55, Gabriel Corona <gabriel.corona at free.fr> a
> écrit :
>
>> In addition to the issue discussed by OP, using $http_host could
>> possibly introduce vulnerabilities to HTTP Host ambiguity attacks.
>>
>> Debian's /etc/nginx/proxy_param uses the following line:
>>
>> proxy_set_header Host $http_host;
>>
>> This configuration is not consistent which what is recommended by
>> NGINX documentation [1]:
>>
>> proxy_set_header Host $host;
>>
>> Note that the nginx-snippets package contains a
>> common-proxy-pass-headers.conf file which includes a correct
>> configuration:
>>
>> proxy_set_header Host $host;
>> proxy_set_header X-Forwarded-Host $host;
>>
>> An attacker can use a HTTP/1 request with ambiguous hosts:
>>
>> GET http://host1/ HTTP/1.1
>> User-Agent: UA
>> Host: host2
>>
>> This type of request is accepted by NGINX when using HTTP/1 only.
>>
>> In this case, with "proxy_set_header Host $http_host;":
>>
>> * server name "host1" is used for virtual host dispatching in NGINX;
>> * server name "host2" is passed to upstream HTTP server.
>>
>> If NGINX is used to apply security restrictions/filtering to a
>> multi-host/multi-tenant backend application, this could be used to apply
>> the NGINX rules of "host1" while targeting upstream "host2.
>>
>> For example:
>>
>> * if NGINX is applying some IP adresse restriction to host2,
>> the attacker can target host2 without these restrictions [a];
>> * if host1 and host2 are using different mTLS configuration,
>> the attackers could use their mTLS keypair for host1 and
>> target host2;
>> * if the upstream server uses the host/authority (probably a bad
>> idea) to build absolute URLs, an attacker could use
>> host-ambiguous requests to generate links to malicious servers
>> (especially with cache poisoning).
>>
>> I reached to NGINX to discuss about this potential host ambiguity and
>> I suggested using a "safer" logic such as:
>>
>> * overriding the Host header with the request line authority if present
>> (same as Apacher httpd, Traefik and Caddy);
>> * rejecting host-ambiguous requests entirely (same as NGINX in HTTP/2,
>> HA Proxy).
>>
>> Their assessment is that this is a configuration error i.e. you
>> should use $host and not $http_host.
>>
>> More generally, other usages of $http_host introduce a host ambiguity
>> issue which might have a security impact (eg. for in proxy_pass,
>> access_log, etc.).
>>
>> [a]:
>>
>> server {
>> listen 443 ssl;
>> server_name host1;
>> ssl_certificate /etc/nginx/ssl/host1.crt;
>> ssl_certificate_key /etc/nginx/ssl/host1.key;
>> location / {
>> proxy_pass http://backend;
>> include proxy_params;
>> }
>> }
>> server {
>> listen 443 ssl;
>> server_name host2;
>> ssl_certificate /etc/nginx/ssl/host2.crt;
>> ssl_certificate_key /etc/nginx/ssl/host2.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;
>> }
>> }
>>
>> [b]:
>>
>> server {
>> listen 443 ssl;
>> server_name host1;
>> ssl_certificate /etc/nginx/ssl/host1.crt;
>> ssl_certificate_key /etc/nginx/ssl/host1.key;
>> ssl_client_certificate /etc/nginx/ssl/ca-host1.crt;
>> ssl_verify_client on;
>> ssl_verify_depth 2;
>> location / {
>> proxy_pass http://backend;
>> include proxy_params;
>> }
>> }
>> server {
>> listen 443 ssl;
>> server_name host2;
>> ssl_certificate /etc/nginx/ssl/host2.crt;
>> ssl_certificate_key /etc/nginx/ssl/host2.key;
>> ssl_client_certificate /etc/nginx/ssl/ca-host1.crt;
>> ssl_verify_client on;
>> ssl_verify_depth 2;
>> location / {
>> proxy_pass http://backend;
>> include proxy_params;
>> }
>> }
>>
>> === Potential fixes/mitigation
>>
>> Mitigation 0: use the hardcoded expected hostname instead of `$http_host`.
>>
>> proxy_set_header Host "www.example.com";
>> proxy_set_header X-Forwarded-Host "www.example.com";
>>
>> Downside: not suitable for NGINX proxy_params.
>>
>> Mitigation 1: use $host instead of $http_host:
>>
>> proxy_set_header Host $host;
>> proxy_set_header X-Forwarded-Host $host;
>>
>> Downside: this not not include the port information which could
>> be a breaking change for some applications.
>
> Mitigation 1: use $host$is_request_port$request_port instead of $http_host:
>>
>> proxy_set_header Host $host$is_request_port$request_port;
>> proxy_set_header X-Forwarded-Host $host$is_request_port$request_port;
>>
>> Downside: only available since NGINX 1.29.3 (not in trixie).
>
>
>> Note: I think the $request_port could be spoofed anyway.
>
>
>> Mitigation 2: use NGINX directive to reject ambiguous (malicious)
>> requests.
>>
>> Either (does not work when using ports):
>>
>> if ($host != $http_host) {
>> return 421 "Ambiguous host";
>> }
>>
>> or:
>>
>> if ($http_host != "$host$is_request_port$request_port") {
>> return 421 "Ambiguous host";
>> }
>>
>> === Q: Should NGINX accept or rejects HTTP requests with host ambiguity?
>>
>> Host-ambiguous requests are accepted by NGINX based on RFC 9112 section
>> 3.2.2 [2]:
>>
>> > When an origin server receives a request with an absolute-form of
>> > request-target, the origin server MUST ignore the received Host
>> > header field (if any) and instead use the host information of
>> > the request-target. Note that if the request-target does not
>> > have an authority component, an empty Host header field
>> > will be sent in this case.
>>
>> NGINX is acting as a reverse proxy and is therefore [3] considered
>> an origin server in this context.
>>
>> On the other hand, I would argue that rejecting the request would make
>> sense as per section 3.2 [4]:
>>
>> > A client MUST send a Host header field (Section 7.2 of [HTTP])
>> > in all HTTP/1.1 request messages. If the target URI includes an
>> > authority component, then a client MUST send a field value for Host
>> > that is identical to that authority component, excluding any
>> > userinfo subcomponent and its "@" delimiter (Section 4.2 of [HTTP]).
>>
>
> It's an nginx feature, so we can't really get in its way.
>
> We should limit ourselves to fixing proxy_params, and that's not going to
> be backported to trixie so I suggest to just wait for nginx 1.30 to be in
> debian,
> and then use $is_request_port.
>
Also I see very odd behavior of http3 with nginx 1.26 (some HTTP3
connections just hang for no reasons).
So until the experimental "tag" is removed from the documentation, I
strongly suggest to not use nginx quic,
except for development.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-nginx-maintainers/attachments/20260305/1630ea8e/attachment.htm>
More information about the Pkg-nginx-maintainers
mailing list