apache/trafficserver

ATS does not validate `Content-Length` values for HTTP/1.1 requests that contain a `Transfer-Encoding: chunked` header.

kenballus opened this issue · 2 comments

The bug

RFC 9110 uses the following ABNF rule to define the acceptable values of the Content-Length header:

Content-Length = 1*DIGIT

When ATS receives a request with no Transfer-Encoding header, and an invalid Content-Length header, it correctly rejects the request.

When ATS receives a request with a Transfer-Encoding: chunked header, and an invalid Content-Length header, it strips the Content-Length header out of the request, but does not reject the request.

RFC 9110 is clear that this is something a send MUST not do:

Likewise, a sender MUST NOT forward a message with a Content-Length header field value that does not match the ABNF above, with one exception: a recipient of a Content-Length header field value consisting of the same decimal value repeated as a comma-separated list (e.g, "Content-Length: 42, 42") MAY either reject the message as invalid or replace that invalid field value with a single instance of the decimal value, since this likely indicates that a duplicate was generated or combined by an upstream message processor.

Reproducing the bug

To verify this for yourself, try sending the following request to ATS:

POST / HTTP/1.1\r\n
Host: a\r\n
Content-Length: blahblahblah\r\n
Transfer-Encoding: chunked\r\n
\r\n
1\r\n
Z\r\n
0\r\n
\r\n

It should forward something like the following to its backend:

POST / HTTP/1.1\r\n
Host: a\r\n
Client-ip: 172.19.0.1\r\n
X-Forwarded-For: 172.19.0.1\r\n
Via: http/1.1 traffic_server[f768a0a3-f9d8-4b7a-841a-4afc6bb85500] (ApacheTrafficServer/10.0.0)\r\n
Transfer-Encoding: chunked\r\n
\r\n
1\r\n
Z\r\n
0\r\n
\r\n

You can reproduce my experimental setup exactly using the HTTP Garden. Just build the Garden, and run the following command at the repl:

transducers ats; payload 'POST / HTTP/1.1\r\nHost: a\r\nContent-Length: blahblahblah\r\nTransfer-Encoding: chunked\r\n\r\n1\r\nZ\r\n0\r\n\r\n'; transduce

You should see something like this:

[1]: 'POST / HTTP/1.1\r\nHost: a\r\nContent-Length: blahblahblah\r\nTransfer-Encoding: chunked\r\n\r\n1\r\nZ\r\n0\r\n\r\n'
    ⬇️ ats
[2]: 'POST / HTTP/1.1\r\nHost: a\r\nClient-ip: 172.19.0.1\r\nX-Forwarded-For: 172.19.0.1\r\nVia: http/1.1 traffic_server[82766f05-99c1-4da5-ae53-267e3c448e08] (ApacheTrafficServer/10.0.0)\r\nTransfer-Encoding: chunked\r\n\r\n1\r\nZ\r\n0\r\n\r\n'

The fact that the message was forwarded demonstrates the bug.

Versions

Traffic Server 10.0.0-0 Feb  2 2024 03:29:51 buildkitsandbox
traffic_server: using root directory '/usr/local/trafficserver'
ats - traffic_server - 10.0.0 - (build # 0 on Feb  2 2024 at 03:15:13)
$ uname -a
Linux 69a420df15e4 6.7.2-arch1-2 #1 SMP PREEMPT_DYNAMIC Wed, 31 Jan 2024 09:22:15 +0000 x86_64 GNU/Linux

The behavior is based on this paragraph.
https://www.rfc-editor.org/rfc/rfc9112#section-6.3-2.3

If a message is received with both a Transfer-Encoding and a Content-Length header field, the Transfer-Encoding overrides the Content-Length. Such a message might indicate an attempt to perform request smuggling (Section 11.2) or response splitting (Section 11.1) and ought to be handled as an error. An intermediary that chooses to forward the message MUST first remove the received Content-Length field and process the Transfer-Encoding (as described below) prior to forwarding the message downstream.

Yep; I think you're right. Closing the issue.