diff -Nru python-urllib3-1.25.8/debian/changelog python-urllib3-1.25.8/debian/changelog --- python-urllib3-1.25.8/debian/changelog 2023-01-18 15:50:06.000000000 +0000 +++ python-urllib3-1.25.8/debian/changelog 2023-10-24 19:57:53.000000000 +0000 @@ -1,3 +1,17 @@ +python-urllib3 (1.25.8-2ubuntu0.3) focal-security; urgency=medium + + * SECURITY UPDATE: http cookie leakage via http redirect + - debian/patches/CVE-2023-43804.patch: removes the cookie from the + http request when it is redirected to a different origin. + - CVE-2023-43804 + * SECURITY UPDATE: http body leakage via http redirect + - debian/patches/CVE-2023-45803.patch: removes the body from the + http request when it is redirected to a different origin and the + http verb is changed to GET. + - CVE-2023-45803 + + -- Jorge Sancho Larraz Tue, 24 Oct 2023 21:57:53 +0200 + python-urllib3 (1.25.8-2ubuntu0.2) focal-security; urgency=medium * SECURITY UPDATE: DoS via URL regex backtracking diff -Nru python-urllib3-1.25.8/debian/patches/CVE-2023-43804.patch python-urllib3-1.25.8/debian/patches/CVE-2023-43804.patch --- python-urllib3-1.25.8/debian/patches/CVE-2023-43804.patch 1970-01-01 00:00:00.000000000 +0000 +++ python-urllib3-1.25.8/debian/patches/CVE-2023-43804.patch 2023-10-24 19:42:08.000000000 +0000 @@ -0,0 +1,132 @@ +From 01220354d389cd05474713f8c982d05c9b17aafb Mon Sep 17 00:00:00 2001 +From: Seth Michael Larson +Date: Mon, 2 Oct 2023 11:43:46 -0500 +Subject: [PATCH] Backport GHSA-v845-jxx5-vc9f (#3139) + +Co-authored-by: Quentin Pradet +Co-authored-by: Illia Volochii +--- + src/urllib3/util/retry.py | 2 +- + test/test_retry.py | 4 ++-- + test/with_dummyserver/test_poolmanager.py | 24 ++++++++++++++++++----- + 3 files changed, 28 insertions(+), 8 deletions(-) + +--- python-urllib3-1.26.5.orig/src/urllib3/util/retry.py ++++ python-urllib3-1.26.5/src/urllib3/util/retry.py +@@ -217,6 +217,6 @@ class Retry(object): + RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503]) + +- DEFAULT_REDIRECT_HEADERS_BLACKLIST = frozenset(["Authorization"]) ++ DEFAULT_REDIRECT_HEADERS_BLACKLIST = frozenset(["Cookie", "Authorization"]) + + #: Maximum backoff time. + BACKOFF_MAX = 120 +--- python-urllib3-1.26.5.orig/test/test_retry.py ++++ python-urllib3-1.26.5/test/test_retry.py +@@ -293,12 +293,12 @@ class TestRetry(object): + def test_retry_default_remove_headers_on_redirect(self): + retry = Retry() + +- assert list(retry.remove_headers_on_redirect) == ["authorization"] ++ assert retry.remove_headers_on_redirect == {"authorization", "cookie"} + + def test_retry_set_remove_headers_on_redirect(self): + retry = Retry(remove_headers_on_redirect=["X-API-Secret"]) + +- assert list(retry.remove_headers_on_redirect) == ["x-api-secret"] ++ assert retry.remove_headers_on_redirect == {"x-api-secret"} + + @pytest.mark.parametrize("value", ["-1", "+1", "1.0", six.u("\xb2")]) # \xb2 = ^2 + def test_parse_retry_after_invalid(self, value): +--- python-urllib3-1.26.5.orig/test/with_dummyserver/test_poolmanager.py ++++ python-urllib3-1.26.5/test/with_dummyserver/test_poolmanager.py +@@ -141,7 +141,7 @@ class TestPoolManager(HTTPDummyServerTes + "GET", + "%s/redirect" % self.base_url, + fields={"target": "%s/headers" % self.base_url_alt}, +- headers={"Authorization": "foo"}, ++ headers={"Authorization": "foo", "Cookie": "foo=bar"}, + ) + + assert r.status == 200 +@@ -149,12 +149,13 @@ class TestPoolManager(HTTPDummyServerTes + data = json.loads(r.data.decode("utf-8")) + + assert "Authorization" not in data ++ assert "Cookie" not in data + + r = http.request( + "GET", + "%s/redirect" % self.base_url, + fields={"target": "%s/headers" % self.base_url_alt}, +- headers={"authorization": "foo"}, ++ headers={"authorization": "foo", "cookie": "foo=bar"}, + ) + + assert r.status == 200 +@@ -163,6 +164,8 @@ class TestPoolManager(HTTPDummyServerTes + + assert "authorization" not in data + assert "Authorization" not in data ++ assert "cookie" not in data ++ assert "Cookie" not in data + + def test_redirect_cross_host_no_remove_headers(self): + with PoolManager() as http: +@@ -170,7 +173,7 @@ class TestPoolManager(HTTPDummyServerTes + "GET", + "%s/redirect" % self.base_url, + fields={"target": "%s/headers" % self.base_url_alt}, +- headers={"Authorization": "foo"}, ++ headers={"Authorization": "foo", "Cookie": "foo=bar"}, + retries=Retry(remove_headers_on_redirect=[]), + ) + +@@ -179,6 +182,7 @@ class TestPoolManager(HTTPDummyServerTes + data = json.loads(r.data.decode("utf-8")) + + assert data["Authorization"] == "foo" ++ assert data["Cookie"] == "foo=bar" + + def test_redirect_cross_host_set_removed_headers(self): + with PoolManager() as http: +@@ -186,7 +190,11 @@ class TestPoolManager(HTTPDummyServerTes + "GET", + "%s/redirect" % self.base_url, + fields={"target": "%s/headers" % self.base_url_alt}, +- headers={"X-API-Secret": "foo", "Authorization": "bar"}, ++ headers={ ++ "X-API-Secret": "foo", ++ "Authorization": "bar", ++ "Cookie": "foo=bar", ++ }, + retries=Retry(remove_headers_on_redirect=["X-API-Secret"]), + ) + +@@ -196,12 +204,17 @@ class TestPoolManager(HTTPDummyServerTes + + assert "X-API-Secret" not in data + assert data["Authorization"] == "bar" ++ assert data["Cookie"] == "foo=bar" + + r = http.request( + "GET", + "%s/redirect" % self.base_url, + fields={"target": "%s/headers" % self.base_url_alt}, +- headers={"x-api-secret": "foo", "authorization": "bar"}, ++ headers={ ++ "x-api-secret": "foo", ++ "authorization": "bar", ++ "cookie": "foo=bar", ++ }, + retries=Retry(remove_headers_on_redirect=["X-API-Secret"]), + ) + +@@ -212,6 +225,7 @@ class TestPoolManager(HTTPDummyServerTes + assert "x-api-secret" not in data + assert "X-API-Secret" not in data + assert data["Authorization"] == "bar" ++ assert data["Cookie"] == "foo=bar" + + def test_raise_on_redirect(self): + with PoolManager() as http: diff -Nru python-urllib3-1.25.8/debian/patches/CVE-2023-45803.patch python-urllib3-1.25.8/debian/patches/CVE-2023-45803.patch --- python-urllib3-1.25.8/debian/patches/CVE-2023-45803.patch 1970-01-01 00:00:00.000000000 +0000 +++ python-urllib3-1.25.8/debian/patches/CVE-2023-45803.patch 2023-10-24 19:57:28.000000000 +0000 @@ -0,0 +1,162 @@ +From b594c5ceaca38e1ac215f916538fb128e3526a36 Mon Sep 17 00:00:00 2001 +From: Illia Volochii +Date: Tue, 17 Oct 2023 19:35:39 +0300 +Subject: [PATCH] Merge pull request from GHSA-g4mx-q9vg-27p4 + +--- + dummyserver/handlers.py | 7 +++++++ + src/urllib3/_collections.py | 18 ++++++++++++++++++ + src/urllib3/connectionpool.py | 5 +++++ + src/urllib3/poolmanager.py | 7 +++++-- + test/with_dummyserver/test_connectionpool.py | 11 +++++++++++ + test/with_dummyserver/test_poolmanager.py | 15 +++++++++++++++ + 6 files changed, 61 insertions(+), 2 deletions(-) + +--- python-urllib3-1.26.5.orig/dummyserver/handlers.py ++++ python-urllib3-1.26.5/dummyserver/handlers.py +@@ -186,6 +186,8 @@ class TestingApp(RequestHandler): + status = request.params.get("status", "303 See Other") + if len(status) == 3: + status = "%s Redirect" % status.decode("latin-1") ++ elif isinstance(status, bytes): ++ status = status.decode("latin-1") + + headers = [("Location", target)] + return Response(status=status, headers=headers) +@@ -264,6 +266,11 @@ class TestingApp(RequestHandler): + def headers(self, request): + return Response(json.dumps(dict(request.headers))) + ++ def headers_and_params(self, request): ++ return Response( ++ json.dumps({"headers": dict(request.headers), "params": request.params}) ++ ) ++ + def successful_retry(self, request): + """ Handler which will return an error and then success + +--- python-urllib3-1.26.5.orig/src/urllib3/_collections.py ++++ python-urllib3-1.26.5/src/urllib3/_collections.py +@@ -268,6 +268,24 @@ class HTTPHeaderDict(MutableMapping): + else: + return vals[1:] + ++ def _prepare_for_method_change(self): ++ """ ++ Remove content-specific header fields before changing the request ++ method to GET or HEAD according to RFC 9110, Section 15.4. ++ """ ++ content_specific_headers = [ ++ "Content-Encoding", ++ "Content-Language", ++ "Content-Location", ++ "Content-Type", ++ "Content-Length", ++ "Digest", ++ "Last-Modified", ++ ] ++ for header in content_specific_headers: ++ self.discard(header) ++ return self ++ + # Backwards compatibility for httplib + getheaders = getlist + getallmatchingheaders = getlist +--- python-urllib3-1.26.5.orig/src/urllib3/connectionpool.py ++++ python-urllib3-1.26.5/src/urllib3/connectionpool.py +@@ -8,6 +8,7 @@ import warnings + from .packages.ssl_match_hostname import CertificateError + import six + from six.moves import queue ++from ._collections import HTTPHeaderDict + from .connection import ( + port_by_scheme, + DummyConnection, +@@ -800,7 +801,11 @@ class HTTPConnectionPool(ConnectionPool, + redirect_location = redirect and response.get_redirect_location() + if redirect_location: + if response.status == 303: ++ # Change the method according to RFC 9110, Section 15.4.4. + method = "GET" ++ # And lose the body not to transfer anything sensitive. ++ body = None ++ headers = HTTPHeaderDict(headers)._prepare_for_method_change() + + try: + retries = retries.increment(method, url, response=response, _pool=self) +--- python-urllib3-1.26.5.orig/src/urllib3/poolmanager.py ++++ python-urllib3-1.26.5/src/urllib3/poolmanager.py +@@ -4,7 +4,7 @@ import collections + import functools + import logging + +-from ._collections import RecentlyUsedContainer ++from ._collections import HTTPHeaderDict, RecentlyUsedContainer + from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool + from .connectionpool import port_by_scheme + from .exceptions import LocationValueError, MaxRetryError, ProxySchemeUnknown +@@ -381,9 +381,12 @@ class PoolManager(RequestMethods): + # Support relative URLs for redirecting. + redirect_location = urljoin(url, redirect_location) + +- # RFC 7231, Section 6.4.4 + if response.status == 303: ++ # Change the method according to RFC 9110, Section 15.4.4. + method = "GET" ++ # And lose the body not to transfer anything sensitive. ++ kw["body"] = None ++ kw["headers"] = HTTPHeaderDict(kw["headers"])._prepare_for_method_change() + + retries = kw.get("retries") + if not isinstance(retries, Retry): +--- python-urllib3-1.26.5.orig/test/with_dummyserver/test_connectionpool.py ++++ python-urllib3-1.26.5/test/with_dummyserver/test_connectionpool.py +@@ -409,6 +409,17 @@ class TestConnectionPool(HTTPDummyServer + assert r.status == 200 + assert r.data == b"Dummy server!" + ++ def test_303_redirect_makes_request_lose_body(self): ++ with HTTPConnectionPool(self.host, self.port) as pool: ++ response = pool.request( ++ "POST", ++ "/redirect", ++ fields={"target": "/headers_and_params", "status": "303 See Other"}, ++ ) ++ data = json.loads(response.data) ++ assert data["params"] == {} ++ assert "Content-Type" not in HTTPHeaderDict(data["headers"]) ++ + def test_bad_connect(self): + with HTTPConnectionPool("badhost.invalid", self.port) as pool: + with pytest.raises(MaxRetryError) as e: +--- python-urllib3-1.26.5.orig/test/with_dummyserver/test_poolmanager.py ++++ python-urllib3-1.26.5/test/with_dummyserver/test_poolmanager.py +@@ -5,6 +5,7 @@ import pytest + + from dummyserver.server import HAS_IPV6 + from dummyserver.testcase import HTTPDummyServerTestCase, IPv6HTTPDummyServerTestCase ++from urllib3._collections import HTTPHeaderDict + from urllib3.poolmanager import PoolManager + from urllib3.connectionpool import port_by_scheme + from urllib3.exceptions import MaxRetryError +@@ -236,6 +237,20 @@ class TestPoolManager(HTTPDummyServerTes + assert data["Authorization"] == "bar" + assert data["Cookie"] == "foo=bar" + ++ def test_303_redirect_makes_request_lose_body(self): ++ with PoolManager() as http: ++ response = http.request( ++ "POST", ++ "%s/redirect" % self.base_url, ++ fields={ ++ "target": "%s/headers_and_params" % self.base_url, ++ "status": "303 See Other", ++ }, ++ ) ++ data = json.loads(response.data) ++ assert data["params"] == {} ++ assert "Content-Type" not in HTTPHeaderDict(data["headers"]) ++ + def test_raise_on_redirect(self): + with PoolManager() as http: + r = http.request( diff -Nru python-urllib3-1.25.8/debian/patches/series python-urllib3-1.25.8/debian/patches/series --- python-urllib3-1.25.8/debian/patches/series 2023-01-18 15:49:33.000000000 +0000 +++ python-urllib3-1.25.8/debian/patches/series 2023-10-24 19:44:08.000000000 +0000 @@ -3,3 +3,5 @@ 05_avoid-embedded-ssl-match-hostname.patch CVE-2020-26137.patch CVE-2021-33503.patch +CVE-2023-43804.patch +CVE-2023-45803.patch