Skip to content

reject transfer-encoding requests in finish_request#2654

Merged
stephenberry merged 2 commits into
stephenberry:mainfrom
uwezkhan:http-reject-transfer-encoding
Jun 20, 2026
Merged

reject transfer-encoding requests in finish_request#2654
stephenberry merged 2 commits into
stephenberry:mainfrom
uwezkhan:http-reject-transfer-encoding

Conversation

@uwezkhan

@uwezkhan uwezkhan commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

The server frames request bodies with Content-Length only and ignores Transfer-Encoding, since chunked request bodies are unsupported. finish_request reaches the Content-Length step with a request that carries Transfer-Encoding and no Content-Length, treats it as a zero-length body, and leaves the encoded payload sitting in the keep-alive buffer. A front-end proxy that does honor Transfer-Encoding forwards the whole thing as one request, so those leftover bytes get parsed here as a second request the client never sent (TE/CL desync, request smuggling).

Before: a Transfer-Encoding request was silently accepted with an empty body and the chunk data was reinterpreted as a pipelined request. After: finish_request answers 501 and closes the connection when a Transfer-Encoding header is present, which RFC 7230 3.3.1 calls for on an encoding the server cannot decode. The check sits next to the Content-Length parsing because that is the layer that frames the body and decides what stays in the buffer; the tradeoff is that a (currently unsupported) chunked client now gets a hard 501 instead of a confusing empty-body 200. Content-Length requests are unaffected.

@annihilatorq

Copy link
Copy Markdown
Collaborator

I'd like to note that RFC 7230 doesn't have a section 6.3.3. The section you're talking about is 3.3.1

@uwezkhan

Copy link
Copy Markdown
Contributor Author

Good catch, that was a typo. It's 3.3.1, where the 501 for an unknown transfer coding lives. Fixed the code comment and the description.

@stephenberry stephenberry merged commit d1b02a5 into stephenberry:main Jun 20, 2026
5 checks passed
stephenberry added a commit that referenced this pull request Jun 20, 2026
…230 3.2.4) (#2661)

A header line using obsolete line folding (obs-fold) or with whitespace between
the field-name and the colon was parsed leniently and stored under a mangled
key. That let an obfuscated Transfer-Encoding ("Transfer-Encoding : chunked", a
tab before the colon, or a value carried on a folded continuation line) slip
past the header lookups that frame the request body: the server saw no
Transfer-Encoding/Content-Length, treated the body as empty, and left the
encoded payload in the keep-alive buffer where it was reparsed as a second,
smuggled request once a folding/whitespace-lenient front-end framed the body as
chunked (TE/CL desync, request smuggling).

try_parse_request now rejects both forms with 400 Bad Request and closes the
connection, as RFC 7230 3.2.4 requires; closing discards the leftover bytes.
Well-formed requests, including header values that contain spaces and colons,
are unaffected.

Complements #2654 (which rejects a clean Transfer-Encoding header); together
they close the obfuscated and non-obfuscated TE/CL desync variants.

Adds http_header_strictness_test covering the space-before-colon, tab-before-
colon, and obs-fold smuggling vectors plus a well-formed positive control.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants