Closed
fix(cve): 修复 CVE-2026-115877 在 python-twisted 中的漏洞 #76
infra_teamAdd on 8 days agoClosed at 2 days ago
fix(cve): 修复 CVE-2026-115877 在 python-twisted 中的漏洞 #76
Closed
infra_teamAdd on 8 days agoClosed at 2 days ago
Total: 3 files changed+113-1
@@ -0,0 +1,31 @@
1+From eea1eb546bde0987c038581a11dcbd33fe081b0b Mon Sep 17 00:00:00 2001
2+From: arkmarta <arkadiuszmarta@proton.me>
3+Date: Fri, 31 Jul 2026 14:30:02 +0200
4+Subject: [PATCH 2/2] web: check a header value for NUL CR and LF in one pass
5+ 
6+Upstream-commit: https://github.com/twisted/twisted/commit/022b6f7feb5980166c71f54e2c0d8f4f21ff6e1a
7+Signed-off-by: infra_team <zhaiwenjie1@huawei.com>
8+---
9+ src/twisted/web/http.py | 6 +++---
10+ 1 file changed, 3 insertions(+), 3 deletions(-)
11+ 
12+diff --git a/src/twisted/web/http.py b/src/twisted/web/http.py
13+index ab9b0c4..2feefa7 100644
14+--- a/src/twisted/web/http.py
15++++ b/src/twisted/web/http.py
16+@@ -2500,9 +2500,9 @@ class HTTPChannel(basic.LineReceiver, policies.TimeoutMixin):
17+ return False
18+
19+ data = data.strip(b" \t")
20+- # Reject NUL, CR, and LF in a header value (RFC 9110 section 5.5); a
21+- # bare CR or LF would let a lenient proxy smuggle a following header.
22+- if b"\x00" in data or b"\r" in data or b"\n" in data:
23++ # A header value must not contain NUL, CR, or LF (RFC 9110 section 5.5).
24++ # A bare CR or LF here would let a lenient proxy smuggle a header.
25++ if len(data.translate(None, b"\x00\r\n")) != len(data):
26+ self._respondToBadRequestAndDisconnect()
27+ return False
28+
29+--
30+2.39.5
31+ 
@@ -0,0 +1,72 @@
1+From c110fd151be7ad0aedef21fce85f8051c54afa0f Mon Sep 17 00:00:00 2001
2+From: arkmarta <arkadiuszmarta@proton.me>
3+Date: Fri, 31 Jul 2026 14:04:59 +0200
4+Subject: [PATCH 1/2] Reject a bare CR or LF in an HTTP header value (#12754)
5+ 
6+Upstream-commit: https://github.com/twisted/twisted/commit/1616f702d36eda8990a5a5b22ad70fab140a7eb1
7+Signed-off-by: infra_team <zhaiwenjie1@huawei.com>
8+---
9+ src/twisted/web/http.py | 4 +++-
10+ src/twisted/web/newsfragments/12754.bugfix | 1 +
11+ src/twisted/web/test/test_http.py | 22 ++++++++++++++++++++++
12+ 3 files changed, 26 insertions(+), 1 deletion(-)
13+ create mode 100644 src/twisted/web/newsfragments/12754.bugfix
14+ 
15+diff --git a/src/twisted/web/http.py b/src/twisted/web/http.py
16+index 29ac7db..ab9b0c4 100644
17+--- a/src/twisted/web/http.py
18++++ b/src/twisted/web/http.py
19+@@ -2500,7 +2500,9 @@ class HTTPChannel(basic.LineReceiver, policies.TimeoutMixin):
20+ return False
21+
22+ data = data.strip(b" \t")
23+- if b"\x00" in data:
24++ # Reject NUL, CR, and LF in a header value (RFC 9110 section 5.5); a
25++ # bare CR or LF would let a lenient proxy smuggle a following header.
26++ if b"\x00" in data or b"\r" in data or b"\n" in data:
27+ self._respondToBadRequestAndDisconnect()
28+ return False
29+
30+diff --git a/src/twisted/web/newsfragments/12754.bugfix b/src/twisted/web/newsfragments/12754.bugfix
31+new file mode 100644
32+index 0000000..9d42c46
33+--- /dev/null
34++++ b/src/twisted/web/newsfragments/12754.bugfix
35+@@ -0,0 +1 @@
36++twisted.web.http.HTTPChannel.headerReceived now rejects a header value that contains a bare carriage return or line feed, closing a request-smuggling gap where such a value could hide a following header from the parser (RFC 9110 section 5.5).
37+diff --git a/src/twisted/web/test/test_http.py b/src/twisted/web/test/test_http.py
38+index a670095..cc17336 100644
39+--- a/src/twisted/web/test/test_http.py
40++++ b/src/twisted/web/test/test_http.py
41+@@ -2211,6 +2211,28 @@ class ParsingTests(unittest.TestCase):
42+ [b"GET / HTTP/1.1", b"Host: foo.example", header, b"", b""]
43+ )
44+
45++ def test_invalidHeaderValueCRLF(self):
46++ """
47++ A header value containing a bare CR or LF is rejected with a 400, as
48++ required by RFC 9110 section 5.5; accepting it would let a following
49++ header be hidden from the parser and enable request smuggling. The bytes
50++ are fed directly because L{runRequest} normalises a bare LF to CRLF.
51++ """
52++ for value in [
53++ b"a\nContent-Length: 5", # bare LF hiding a header
54++ b"a\rContent-Length: 5", # bare CR hiding a header
55++ b"a\nb", # bare LF
56++ b"a\rb", # bare CR
57++ ]:
58++ channel = http.HTTPChannel()
59++ transport = StringTransport()
60++ channel.makeConnection(transport)
61++ channel.dataReceived(
62++ b"GET / HTTP/1.1\r\nHost: foo.example\r\nx-foo: " + value + b"\r\n\r\n"
63++ )
64++ self.assertTrue(transport.disconnecting)
65++ self.assertEqual(transport.value(), b"HTTP/1.1 400 Bad Request\r\n\r\n")
66++
67+ def test_headerLimitPerRequest(self):
68+ """
69+ C{HTTPChannel} enforces the limit of C{HTTPChannel.maxHeaders} per
70+--
71+2.39.5
72+ 
@@ -1,12 +1,14 @@
1%define debug_package %{nil}1%define debug_package %{nil}
2Name: python-twisted2Name: python-twisted
3Version: 26.4.03Version: 26.4.0
4-Release: 24+Release: 3
5Summary: An event-driven networking engine written in Python5Summary: An event-driven networking engine written in Python
6License: MIT6License: MIT
7URL: http://twistedmatrix.com/7URL: http://twistedmatrix.com/
8Source0: https://github.com/twisted/twisted/archive/refs/tags/twisted-26.4.0.tar.gz8Source0: https://github.com/twisted/twisted/archive/refs/tags/twisted-26.4.0.tar.gz
9Patch0: backport-CVE-2026-106454.patch9Patch0: backport-CVE-2026-106454.patch
10+Patch1: backport-CVE-2026-115877-1616f702.patch
11+Patch2: backport-CVE-2026-115877-022b6f7f.patch
10BuildRequires: python3-pip python3-hatchling python3-hatch-vcs python3-wheel12BuildRequires: python3-pip python3-hatchling python3-hatch-vcs python3-wheel
11BuildRequires: python3-hatch-fancy-pypi-readme python3-incremental13BuildRequires: python3-hatch-fancy-pypi-readme python3-incremental
12 14 
@@ -111,6 +113,13 @@ PATH=%{buildroot}%{_bindir}:$PATH PYTHONPATH=%{buildroot}%{python3_sitelib} %{bu
111%{_mandir}/man1/{cftp.1*,ckeygen.1*,conch.1*,mailmail.1*,pyhtmlizer.1*,tkconch.1*,trial.1*,twistd.1*}113%{_mandir}/man1/{cftp.1*,ckeygen.1*,conch.1*,mailmail.1*,pyhtmlizer.1*,tkconch.1*,trial.1*,twistd.1*}
112 114 
113%changelog115%changelog
116+* Sat Oct 31 2026 infra_team <zhaiwenjie1@huawei.com> - 26.4.0-3
117+- fix CVE: CVE-2026-115877
118+- Backport upstream fix to reject header values containing a bare CR or LF
119+ in twisted.web.http.HTTPChannel.headerReceived, closing a request-smuggling
120+ gap where such a value could hide a following header from the parser
121+ (RFC 9110 section 5.5)
122+ 
114* Wed Oct 14 2026 infra_team <zhaiwenjie1@huawei.com> - 26.4.0-2123* Wed Oct 14 2026 infra_team <zhaiwenjie1@huawei.com> - 26.4.0-2
115- fix CVE: CVE-2026-106454124- fix CVE: CVE-2026-106454
116- Backport upstream fix to escape IMAP wildcards and metacharacters125- Backport upstream fix to escape IMAP wildcards and metacharacters