{"id":"HSEC-2026-0013","summary":"HTTP Request Smuggling in warp","details":"# HTTP Request Smuggling in warp\n\nwarp's HTTP/1.x request parser accepted request framing that RFC 9112 requires recipients to refuse, so a request could frame one way for a front-end proxy reading it and another way for warp behind it. Whoever reads such a request the other way sees one request where the other sees two, which smuggles a request past the proxy: past access control, request validation, logging, or WAF rules. warp's HTTP/2 support delegates parsing to the `http2` package and is not affected.\n\nSix defects were fixed in warp 3.4.17:\n\n* `Transfer-Encoding` and `Content-Length` field lines were collapsed to a single value, the last line winning. A second `Content-Length` could hide the first, and a second `Transfer-Encoding` could hide a `chunked` coding.\n* Sending `Content-Length` together with `Transfer-Encoding`, or a `Transfer-Encoding` whose final coding is not `chunked`, was not refused; warp resolved the ambiguity by reading whichever framing it recognised.\n* `Content-Length` values were parsed by reading the leading digits: a non-numeric value, or one too large for an `Int` which then wrapped, became length 0 — so the request body was read as the next request on the connection.\n* Header field names were not validated: an obs-fold continuation line, a name containing whitespace or control characters, or an empty name became a header warp did not act on but a repairing intermediary could, including a hidden `Content-Length`.\n* A bare CR or a NUL inside a header field line was accepted; an intermediary that takes a bare CR for a line terminator reads a field line where warp reads none.\n* The chunked body parser did not keep to RFC 9112: a chunk size was the fold of whatever hex digits a line led with, a chunk not closed off by CRLF ended the body early, a size line split over several reads was mis-read, and the trailer section was left in the connection to be parsed as the next request. A chunked body cut short by the end of input was handed to the application as though it were whole (yesodweb/wai#1129), so an upload could be stored truncated and answered 200.\n\nExploitation of the framing defects requires a front-end — reverse proxy, load balancer, WAF — that parses the ambiguous request differently from warp; the truncated-chunk defect also affects directly exposed servers.\n\n## Resolution\n\nwarp 3.4.17 validates the framing and refuses requests it cannot frame reliably, raising `InvalidRequest` with the new constructors `UnsupportedTransferEncoding`, `AmbiguousBodyLength`, `BadFieldName`, `BadHeaderLine` and `BadChunkedBody`; the default exception response is 400, or 501 for a transfer coding warp cannot decode.\n\nUsers are advised to upgrade to warp 3.4.17 or later. The lax parsing is verified back to warp 1.3.3, the oldest source retained in the upstream repository's tags; older release series are unsupported and should be upgraded regardless.\n","modified":"2026-11-04T13:00:02.664490250Z","published":"2026-11-04T12:43:59Z","database_specific":{"osvs":"https://raw.githubusercontent.com/haskell/security-advisories/refs/heads/generated/osv-export","repository":"https://github.com/haskell/security-advisories","home":"https://github.com/haskell/security-advisories"},"references":[{"type":"REPORT","url":"https://github.com/yesodweb/wai/issues/1129"},{"type":"FIX","url":"https://github.com/yesodweb/wai/compare/warp-3.4.16...warp-3.4.17"},{"type":"PACKAGE","url":"https://hackage.haskell.org/package/warp"}],"affected":[{"package":{"name":"warp","ecosystem":"Hackage","purl":"pkg:hackage/warp"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.3.3"},{"fixed":"3.4.17"}]}],"versions":["1.3.10","1.3.10.1","1.3.10.2","1.3.3","1.3.3.1","1.3.3.2","1.3.3.3","1.3.4","1.3.4.1","1.3.4.2","1.3.4.3","1.3.4.4","1.3.5","1.3.5.1","1.3.6","1.3.7","1.3.7.1","1.3.7.2","1.3.7.3","1.3.7.4","1.3.7.5","1.3.8","1.3.8.1","1.3.8.2","1.3.8.3","1.3.8.4","1.3.9","1.3.9.1","1.3.9.2","2.0.0","2.0.0.1","2.0.1","2.0.2","2.0.2.1","2.0.3","2.0.3.1","2.0.3.2","2.0.3.3","2.0.3.4","2.1.0","2.1.1","2.1.1.1","2.1.1.2","2.1.2","2.1.2.1","2.1.3","2.1.3.1","2.1.3.2","2.1.3.3","2.1.4","2.1.4.1","2.1.5","2.1.5.1","2.1.5.2","3.0.0","3.0.0.1","3.0.0.2","3.0.0.3","3.0.0.4","3.0.0.5","3.0.0.6","3.0.0.7","3.0.0.8","3.0.1","3.0.1.1","3.0.10","3.0.10.1","3.0.11","3.0.12","3.0.12.1","3.0.13","3.0.13.1","3.0.2","3.0.2.1","3.0.2.2","3.0.2.3","3.0.3","3.0.4","3.0.4.1","3.0.5","3.0.5.1","3.0.5.2","3.0.6","3.0.7","3.0.8","3.0.9","3.0.9.1","3.0.9.2","3.0.9.3","3.1.0","3.1.1","3.1.10","3.1.11","3.1.12","3.1.2","3.1.3","3.1.3.1","3.1.4","3.1.5","3.1.6","3.1.7","3.1.8","3.1.9","3.2.0","3.2.1","3.2.10","3.2.11","3.2.11.1","3.2.11.2","3.2.12","3.2.13","3.2.15","3.2.16","3.2.17","3.2.18","3.2.18.1","3.2.18.2","3.2.19","3.2.2","3.2.20","3.2.21","3.2.22","3.2.23","3.2.24","3.2.25","3.2.26","3.2.27","3.2.28","3.2.3","3.2.4","3.2.5","3.2.6","3.2.7","3.2.8","3.2.9","3.3.0","3.3.1","3.3.10","3.3.11","3.3.12","3.3.13","3.3.14","3.3.15","3.3.16","3.3.17","3.3.18","3.3.19","3.3.2","3.3.20","3.3.21","3.3.22","3.3.23","3.3.24","3.3.25","3.3.26","3.3.27","3.3.28","3.3.29","3.3.3","3.3.30","3.3.31","3.3.4","3.3.5","3.3.6","3.3.7","3.3.8","3.3.9","3.4.0","3.4.1","3.4.10","3.4.11","3.4.12","3.4.13","3.4.13.1","3.4.14","3.4.15","3.4.16","3.4.2","3.4.3","3.4.4","3.4.5","3.4.6","3.4.7","3.4.8","3.4.9"],"database_specific":{"osv":"https://raw.githubusercontent.com/haskell/security-advisories/refs/heads/generated/osv-export/2026/HSEC-2026-0013.json","source":"https://github.com/haskell/security-advisories/blob/generated/osv-export/2026/HSEC-2026-0013.json","human_link":"https://github.com/haskell/security-advisories/tree/main/advisories/published/2026/HSEC-2026-0013.md"},"severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L"}]}],"schema_version":"1.9.2"}