Control: tags 1125062 + patch Control: tags 1125062 + pending
Dear maintainer, I've prepared an NMU for python-urllib3 (versioned as 2.5.0-1.2) and uploaded it to DELAYED/5. Please feel free to tell me if I should cancel it. Regards, Salvatore
diffstat for python-urllib3-2.5.0 python-urllib3-2.5.0 changelog | 8 +++ patches/CVE-2026-21441.patch | 91 +++++++++++++++++++++++++++++++++++++++++++ patches/series | 1 3 files changed, 100 insertions(+) diff -Nru python-urllib3-2.5.0/debian/changelog python-urllib3-2.5.0/debian/changelog --- python-urllib3-2.5.0/debian/changelog 2026-01-03 20:00:44.000000000 +0100 +++ python-urllib3-2.5.0/debian/changelog 2026-01-10 15:16:31.000000000 +0100 @@ -1,3 +1,11 @@ +python-urllib3 (2.5.0-1.2) unstable; urgency=medium + + * Non-maintainer upload. + * Decompression-bomb safeguards bypassed when following HTTP redirects + (streaming API) (CVE-2026-21441) (Closes: #1125062) + + -- Salvatore Bonaccorso <[email protected]> Sat, 10 Jan 2026 15:16:31 +0100 + python-urllib3 (2.5.0-1.1) unstable; urgency=medium * Non-maintainer upload. diff -Nru python-urllib3-2.5.0/debian/patches/CVE-2026-21441.patch python-urllib3-2.5.0/debian/patches/CVE-2026-21441.patch --- python-urllib3-2.5.0/debian/patches/CVE-2026-21441.patch 1970-01-01 01:00:00.000000000 +0100 +++ python-urllib3-2.5.0/debian/patches/CVE-2026-21441.patch 2026-01-10 15:16:02.000000000 +0100 @@ -0,0 +1,91 @@ +From: Illia Volochii <[email protected]> +Date: Wed, 7 Jan 2026 18:07:30 +0200 +Subject: Merge commit from fork +Origin: https://github.com/urllib3/urllib3/commit/8864ac407bba8607950025e0979c4c69bc7abc7b +Bug-Debian: https://bugs.debian.org/1125062 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2026-21441 + +* Stop decoding response content during redirects needlessly + +* Rename the new query parameter + +* Add a changelog entry +--- + CHANGES.rst | 13 +++++++++++++ + dummyserver/app.py | 8 +++++++- + src/urllib3/response.py | 6 +++++- + test/with_dummyserver/test_connectionpool.py | 19 +++++++++++++++++++ + 4 files changed, 44 insertions(+), 2 deletions(-) + +diff --git a/dummyserver/app.py b/dummyserver/app.py +index 0eeb93f7396e..5b82e9329d88 100644 +--- a/dummyserver/app.py ++++ b/dummyserver/app.py +@@ -233,10 +233,16 @@ async def redirect() -> ResponseReturnValue: + values = await request.values + target = values.get("target", "/") + status = values.get("status", "303 See Other") ++ compressed = values.get("compressed") == "true" + status_code = status.split(" ")[0] + + headers = [("Location", target)] +- return await make_response("", status_code, headers) ++ if compressed: ++ headers.append(("Content-Encoding", "gzip")) ++ data = gzip.compress(b"foo") ++ else: ++ data = b"" ++ return await make_response(data, status_code, headers) + + + @hypercorn_app.route("/redirect_after") +diff --git a/src/urllib3/response.py b/src/urllib3/response.py +index f6266f1a938f..ff6d1f4911c2 100644 +--- a/src/urllib3/response.py ++++ b/src/urllib3/response.py +@@ -797,7 +797,11 @@ class HTTPResponse(BaseHTTPResponse): + Unread data in the HTTPResponse connection blocks the connection from being released back to the pool. + """ + try: +- self.read() ++ self.read( ++ # Do not spend resources decoding the content unless ++ # decoding has already been initiated. ++ decode_content=self._has_decoded_content, ++ ) + except (HTTPError, OSError, BaseSSLError, HTTPException): + pass + +diff --git a/test/with_dummyserver/test_connectionpool.py b/test/with_dummyserver/test_connectionpool.py +index ce165e24a1ce..8d6107aea039 100644 +--- a/test/with_dummyserver/test_connectionpool.py ++++ b/test/with_dummyserver/test_connectionpool.py +@@ -508,6 +508,25 @@ class TestConnectionPool(HypercornDummyServerTestCase): + assert r.status == 200 + assert r.data == b"Dummy server!" + ++ @mock.patch("urllib3.response.GzipDecoder.decompress") ++ def test_no_decoding_with_redirect_when_preload_disabled( ++ self, gzip_decompress: mock.MagicMock ++ ) -> None: ++ """ ++ Test that urllib3 does not attempt to decode a gzipped redirect ++ response when `preload_content` is set to `False`. ++ """ ++ with HTTPConnectionPool(self.host, self.port) as pool: ++ # Three requests are expected: two redirects and one final / 200 OK. ++ response = pool.request( ++ "GET", ++ "/redirect", ++ fields={"target": "/redirect?compressed=true", "compressed": "true"}, ++ preload_content=False, ++ ) ++ assert response.status == 200 ++ gzip_decompress.assert_not_called() ++ + def test_303_redirect_makes_request_lose_body(self) -> None: + with HTTPConnectionPool(self.host, self.port) as pool: + response = pool.request( +-- +2.51.0 + diff -Nru python-urllib3-2.5.0/debian/patches/series python-urllib3-2.5.0/debian/patches/series --- python-urllib3-2.5.0/debian/patches/series 2026-01-03 19:56:35.000000000 +0100 +++ python-urllib3-2.5.0/debian/patches/series 2026-01-10 15:14:58.000000000 +0100 @@ -1,2 +1,3 @@ test_http2_probe_blocked_per_thread-requires_network.patch CVE-2025-66418.patch +CVE-2026-21441.patch

