Skip to content
Medium 5.4

Twisted: HTTP Request Smuggling in twisted.web via a Bare CR or LF in a Header Value

CVE-2026-115877 First seen on SecPulse

Affected packages

EcosystemPackageAffectedFixed
twisted twisted — —
pip Twisted
< 26.10.0rc1
26.10.0rc1
PyPI twisted
< 26.10.0rc1
26.10.0rc1
Original description The description as published by the source.

Summary

An incomplete header-value validation (CWE-444) in the Twisted HTTP server lets a bare carriage return or line feed in a header value hide a following header from the parser. twisted.web.http.HTTPChannel.headerReceived rejects a NUL byte in a header value but not a bare CR or LF, even though RFC 9110 section 5.5 requires a recipient to reject all three. Because the channel splits requests only on CRLF, a value carrying a bare LF and a second header arrives as one line, so the second header is folded into the value and the request is framed with no body. A front-end that treats the bare LF as a line terminator frames the request differently, and the disagreement lets an attacker smuggle a request past it. This is an incomplete fix of the earlier Twisted request-smuggling advisories, which guarded the NUL sibling of this exact check.

Details

headerReceived splits a header line on the first colon, strips space and tab from the value, and validates it with a single test that rejects only NUL:

# twisted/web/http.py  HTTPChannel.headerReceived
data = data.strip(b" \t")
if b"\x00" in data:          # NUL rejected; a bare CR or LF is not
    self._respondToBadRequestAndDisconnect()
    return False

The channel delimiter is CRLF, so Foo: x\nContent-Length: 39 is one line: the split yields name Foo and value x\nContent-Length: 39, strip leaves the LF, and the NUL check passes. _maybeChooseTransferDecoder is then called with Foo, never se…

Source: CVE.org (CVE Program・cvelistV5) NVD GitHub Advisory

References

We use cookies for analytics and ad measurement. This setting applies to all Game co., Ltd. sites. Details