Summary
Mint's HTTP/1 chunked-body decoder parses chunk-size lines with Integer.parse(data, 16), which accepts a leading + or - in violation of RFC 7230. On a pooled keep-alive connection that traverses an RFC-strict intermediary, a malicious origin can send sign-prefixed chunk sizes that Mint accepts but the intermediary rejects, producing a response-smuggling primitive against subsequent requests on the connection.
Details
Mint.HTTP1.decode_body/5 in lib/mint/http1.ex dispatches on Integer.parse(data, 16) when reading the next chunk-size line. Because Integer.parse/2 treats a leading +/- as an optional sign:
+5 is accepted as a five-byte chunk.
+0 and -0 are accepted as the terminating zero-length chunk and end the body early.
- Only
-5 and other negative non-zero values fall through to :invalid_chunk_size.
A strict RFC 7230 parser rejects any sign in chunk-size, so Mint and an intermediary in the response path disagree on chunk boundaries. On a pooled keep-alive connection the origin can emit trailing bytes that the intermediary treats as body but Mint reads as the next response, poisoning the response queue for other in-flight requests on the shared socket.
The fix introduces Mint.HTTP1.Parse.chunk_size/1 in lib/mint/http1/parse.ex, a strict HEXDIG-only parser that rejects any sign or non-hex prefix, and switches decode_body/5 to use it.
PoC
- Point a Mint HTTP/1 client at an attacker-controlled origin through a strict HTTP/1 intermediary that reuses keep-alive connections.
- Have the origin respond with
Transfer-Encoding: chunked and a first chunk-size line of +0\r\n\r\n, followed by a crafted second "response" starting with HTTP/1.1 200 OK\r\n....
- The intermediary rejects
+0 and keeps reading; Mint treats +0 as the last chunk and parses the crafted bytes as the next response on the pooled connection.
Impact
An attacker who controls or influences an HTTP/1 origin that a Mint client talks to through an RFC-strict pooled intermediary can inject responses that Mint attributes to unrelated in-flight requests, corrupting response bodies, headers, or status codes seen by the application.
References
Summary
Mint's HTTP/1 chunked-body decoder parses
chunk-sizelines withInteger.parse(data, 16), which accepts a leading+or-in violation of RFC 7230. On a pooled keep-alive connection that traverses an RFC-strict intermediary, a malicious origin can send sign-prefixed chunk sizes that Mint accepts but the intermediary rejects, producing a response-smuggling primitive against subsequent requests on the connection.Details
Mint.HTTP1.decode_body/5inlib/mint/http1.exdispatches onInteger.parse(data, 16)when reading the next chunk-size line. BecauseInteger.parse/2treats a leading+/-as an optional sign:+5is accepted as a five-byte chunk.+0and-0are accepted as the terminating zero-length chunk and end the body early.-5and other negative non-zero values fall through to:invalid_chunk_size.A strict RFC 7230 parser rejects any sign in
chunk-size, so Mint and an intermediary in the response path disagree on chunk boundaries. On a pooled keep-alive connection the origin can emit trailing bytes that the intermediary treats as body but Mint reads as the next response, poisoning the response queue for other in-flight requests on the shared socket.The fix introduces
Mint.HTTP1.Parse.chunk_size/1inlib/mint/http1/parse.ex, a strictHEXDIG-only parser that rejects any sign or non-hex prefix, and switchesdecode_body/5to use it.PoC
Transfer-Encoding: chunkedand a first chunk-size line of+0\r\n\r\n, followed by a crafted second "response" starting withHTTP/1.1 200 OK\r\n....+0and keeps reading; Mint treats+0as the last chunk and parses the crafted bytes as the next response on the pooled connection.Impact
An attacker who controls or influences an HTTP/1 origin that a Mint client talks to through an RFC-strict pooled intermediary can inject responses that Mint attributes to unrelated in-flight requests, corrupting response bodies, headers, or status codes seen by the application.
References