HTTP request smuggling

Hans Middelhoek hans at
Wed Jun 30 17:03:57 UTC 2021

Hi Maxim,

Thanks! That makes sense to me. I like to understand things a little 
better and hope you can help with that:

1) Why is the result different when I disable keepalive in Nginx? After 
disabling keepalive the second request isn't executed anymore.

2) Do you know why Apache respond the same as Nginx with keepalive disabled?

Op 30-6-2021 om 18:13 schreef Maxim Dounin:
> Hello!
> On Wed, Jun 30, 2021 at 05:01:11PM +0200, Hans Middelhoek wrote:
>> Recently I got a report from a security researcher who said I'm
>> vulnerable for HTTP request smuggling attacks and included a
>> demonstration. I couldn't imagine he was right because I'm using
>> HTTP/1.0 connections between Nginx (reverse proxy) and Apache. It should
>> only be possible when Nginx and Apache are reusing their connections, in
>> real life that means they're using keepalive but that's not possible
>> with HTTP/1.0 and therefore my setup shouldn't be vulnerable to this attack.
>> I tested his demonstration and am able to get the same result. Strange
>> thing is that I also get this outcome with Nginx as standalone
>> webserver, tested with different versions from 1.13.3 to 1.19.6 with
>> default configuration on Debian Stretch.
>> I used the Request Editor of OWASP ZAP (zaproxy) to test the following
>> request:
>> ------------------------------
>> POST / HTTP/1.1
>> Transfer-Encoding: chunked
>> Content-Length: 32
>> Foo: bar
>> Host:
>> 0
>> GET /admin7 HTTP/1.1
>> X-Foo: k
>> ------------------------------
>> Processing the request twice results in a 405 (not allowed) the first
>> time and 404 (not found) the second time. The Nginx logs show the
>> /admin7 GET request the second time.
>> When I set keepalive_timeout 0; this doesn't work anymore. The same
>> request doesn't work on Apache 2.4 with keepalive enabled. It seems like
>> Nginx is vulnerable to this type of attack, what am I missing?
> The provided listing contains two separate requests, the "POST /"
> request with an empty body using chunked transfer encoding, and
> the "GET /admin7" request.
> Note that "Transfer-Encoding: chunked" takes precedence over the
> "Content-Length: 32", see RFC 7230, section 3.3.3 "Message Body
> Length" for details
> (
>         If a message is received with both a Transfer-Encoding and a
>         Content-Length header field, the Transfer-Encoding overrides the
>         Content-Length.
> Unfortunately, many "security researchers" out there do not know
> how HTTP works, and generate many false reports.
> Hope this helps.

More information about the nginx mailing list