Version in base suite: 2.3.0-3 Base version: python-urllib3_2.3.0-3 Target version: python-urllib3_2.3.0-3+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/p/python-urllib3/python-urllib3_2.3.0-3.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/p/python-urllib3/python-urllib3_2.3.0-3+deb13u1.dsc changelog | 10 ++++ patches/CVE-2025-66418.patch | 75 +++++++++++++++++++++++++++++++++++ patches/CVE-2026-21441.patch | 91 +++++++++++++++++++++++++++++++++++++++++++ patches/series | 2 4 files changed, 178 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp4y7jg42g/python-urllib3_2.3.0-3.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp4y7jg42g/python-urllib3_2.3.0-3+deb13u1.dsc: no acceptable signature found diff -Nru python-urllib3-2.3.0/debian/changelog python-urllib3-2.3.0/debian/changelog --- python-urllib3-2.3.0/debian/changelog 2025-07-13 12:09:35.000000000 +0000 +++ python-urllib3-2.3.0/debian/changelog 2026-01-12 21:38:24.000000000 +0000 @@ -1,3 +1,13 @@ +python-urllib3 (2.3.0-3+deb13u1) trixie-security; urgency=high + + * Non-maintainer upload by the Security Team. + * Unbounded number of links in the decompression chain (CVE-2025-66418) + (Closes: #1122030) + * Decompression-bomb safeguards bypassed when following HTTP redirects + (streaming API) (CVE-2026-21441) (Closes: #1125062) + + -- Salvatore Bonaccorso Mon, 12 Jan 2026 22:38:24 +0100 + python-urllib3 (2.3.0-3) unstable; urgency=medium * Team upload. diff -Nru python-urllib3-2.3.0/debian/patches/CVE-2025-66418.patch python-urllib3-2.3.0/debian/patches/CVE-2025-66418.patch --- python-urllib3-2.3.0/debian/patches/CVE-2025-66418.patch 1970-01-01 00:00:00.000000000 +0000 +++ python-urllib3-2.3.0/debian/patches/CVE-2025-66418.patch 2026-01-03 20:31:40.000000000 +0000 @@ -0,0 +1,75 @@ +From: Illia Volochii +Date: Fri, 5 Dec 2025 16:41:33 +0200 +Subject: Merge commit from fork +Origin: https://github.com/urllib3/urllib3/commit/24d7b67eac89f94e11003424bcf0d8f7b72222a8 +Bug-Debian: https://bugs.debian.org/1122030 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2025-66418 + +* Add a hard-coded limit for the decompression chain + +* Reuse new list +--- + changelog/GHSA-gm62-xv2j-4w53.security.rst | 4 ++++ + src/urllib3/response.py | 12 +++++++++++- + test/test_response.py | 10 ++++++++++ + 3 files changed, 25 insertions(+), 1 deletion(-) + create mode 100644 changelog/GHSA-gm62-xv2j-4w53.security.rst + +diff --git a/changelog/GHSA-gm62-xv2j-4w53.security.rst b/changelog/GHSA-gm62-xv2j-4w53.security.rst +new file mode 100644 +index 000000000000..6646eaa3a6c0 +--- /dev/null ++++ b/changelog/GHSA-gm62-xv2j-4w53.security.rst +@@ -0,0 +1,4 @@ ++Fixed a security issue where an attacker could compose an HTTP response with ++virtually unlimited links in the ``Content-Encoding`` header, potentially ++leading to a denial of service (DoS) attack by exhausting system resources ++during decoding. The number of allowed chained encodings is now limited to 5. +diff --git a/src/urllib3/response.py b/src/urllib3/response.py +index 4ba421369f87..069f726cb85a 100644 +--- a/src/urllib3/response.py ++++ b/src/urllib3/response.py +@@ -306,8 +306,18 @@ class MultiDecoder(ContentDecoder): + they were applied. + """ + ++ # Maximum allowed number of chained HTTP encodings in the ++ # Content-Encoding header. ++ max_decode_links = 5 ++ + def __init__(self, modes: str) -> None: +- self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")] ++ encodings = [m.strip() for m in modes.split(",")] ++ if len(encodings) > self.max_decode_links: ++ raise DecodeError( ++ "Too many content encodings in the chain: " ++ f"{len(encodings)} > {self.max_decode_links}" ++ ) ++ self._decoders = [_get_decoder(e) for e in encodings] + + def flush(self) -> bytes: + return self._decoders[0].flush() +diff --git a/test/test_response.py b/test/test_response.py +index 9592fdd94052..d824ae70b41b 100644 +--- a/test/test_response.py ++++ b/test/test_response.py +@@ -847,6 +847,16 @@ class TestResponse: + assert r.read(9 * 37) == b"foobarbaz" * 37 + assert r.read() == b"" + ++ def test_read_multi_decoding_too_many_links(self) -> None: ++ fp = BytesIO(b"foo") ++ with pytest.raises( ++ DecodeError, match="Too many content encodings in the chain: 6 > 5" ++ ): ++ HTTPResponse( ++ fp, ++ headers={"content-encoding": "gzip, deflate, br, zstd, gzip, deflate"}, ++ ) ++ + def test_body_blob(self) -> None: + resp = HTTPResponse(b"foo") + assert resp.data == b"foo" +-- +2.51.0 + diff -Nru python-urllib3-2.3.0/debian/patches/CVE-2026-21441.patch python-urllib3-2.3.0/debian/patches/CVE-2026-21441.patch --- python-urllib3-2.3.0/debian/patches/CVE-2026-21441.patch 1970-01-01 00:00:00.000000000 +0000 +++ python-urllib3-2.3.0/debian/patches/CVE-2026-21441.patch 2026-01-12 21:38:24.000000000 +0000 @@ -0,0 +1,91 @@ +From: Illia Volochii +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.3.0/debian/patches/series python-urllib3-2.3.0/debian/patches/series --- python-urllib3-2.3.0/debian/patches/series 2025-07-13 12:09:35.000000000 +0000 +++ python-urllib3-2.3.0/debian/patches/series 2026-01-12 21:38:24.000000000 +0000 @@ -3,3 +3,5 @@ httpx-0.28.patch CVE-2025-50181.patch CVE-2025-50182.patch +CVE-2025-66418.patch +CVE-2026-21441.patch