Package: release.debian.org
Severity: normal
Tags: bookworm
X-Debbugs-Cc: python-urll...@packages.debian.org
Control: affects -1 + src:python-urllib3
User: release.debian....@packages.debian.org
Usertags: pu

[ Reason ]

Fix 3 no-dsa vulnerabilities (CVE-2023-43804, CVE-2023-45803 and
CVE-2024-37891) and a bug where urllib3.util.ssltransport fails to load
(#1089507).

[ Impact ]

Bookworm users will remain vulnerable.  Also the issues were fixed in
Bullseye LTS, so users upgrading to Bookworm will regress if it isn't
fixed to that suite too.

[ Tests ]

The 3 vulnerabilities come with unit tests.  ssltransport.py is covered
by unit tests too; those ones are currently ignored at build time and
autopkgtests, but were tested manually.

[ Risks ]

The fixes are trivial: 1.26.x is officially supported upstream and the
patches were backported to 1.26.12 without conflict.

[ Checklist ]

  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in stable
  [x] the issue is verified as fixed in unstable

[ Changes ]

  * Fix CVE-2023-43804: Cookie request header isn't stripped during
    cross-origin redirects. (Closes: #1053626)
  * Fix CVE-2023-45803: Request body not stripped after redirect from 303
    status changes request method to GET. (Closes: #1054226)
  * Fix CVE-2024-37891: Proxy-Authorization request header isn't stripped
    during cross-origin redirects. (Closes: #1074149)
  * Use system 'six' module in urllib3.util.ssltransport. (Closes: #1089507)
  * Fix test/test_connectionpool.py (currently ignored).
  * Adjust d/salsa-ci.yml for bookworm.
  * Adjust d/gbp.conf for bookworm.

-- 
Guilhem.
diffstat for python-urllib3-1.26.12 python-urllib3-1.26.12

 changelog                                       |   16 ++
 gbp.conf                                        |    2 
 patches/01_do-not-use-embedded-python-six.patch |   23 ++-
 patches/CVE-2023-43804.patch                    |  157 +++++++++++++++++++++
 patches/CVE-2023-45803.patch                    |  177 ++++++++++++++++++++++++
 patches/CVE-2024-37891.patch                    |  164 ++++++++++++++++++++++
 patches/series                                  |    3 
 salsa-ci.yml                                    |    5 
 8 files changed, 541 insertions(+), 6 deletions(-)

diff -Nru python-urllib3-1.26.12/debian/changelog 
python-urllib3-1.26.12/debian/changelog
--- python-urllib3-1.26.12/debian/changelog     2022-09-22 23:14:17.000000000 
+0200
+++ python-urllib3-1.26.12/debian/changelog     2024-12-21 15:28:17.000000000 
+0100
@@ -1,3 +1,19 @@
+python-urllib3 (1.26.12-1+deb12u1) bookworm; urgency=medium
+
+  * Non-maintainer upload.
+  * Fix CVE-2023-43804: Cookie request header isn't stripped during
+    cross-origin redirects. (Closes: #1053626)
+  * Fix CVE-2023-45803: Request body not stripped after redirect from 303
+    status changes request method to GET. (Closes: #1054226)
+  * Fix CVE-2024-37891: Proxy-Authorization request header isn't stripped
+    during cross-origin redirects. (Closes: #1074149)
+  * Use system 'six' module in urllib3.util.ssltransport. (Closes: #1089507)
+  * Fix test/test_connectionpool.py (currently ignored).
+  * Adjust d/salsa-ci.yml for bookworm.
+  * Adjust d/gbp.conf for bookworm.
+
+ -- Guilhem Moulin <guil...@debian.org>  Sat, 21 Dec 2024 15:28:17 +0100
+
 python-urllib3 (1.26.12-1) unstable; urgency=medium
 
   * Team upload.
diff -Nru python-urllib3-1.26.12/debian/gbp.conf 
python-urllib3-1.26.12/debian/gbp.conf
--- python-urllib3-1.26.12/debian/gbp.conf      2022-08-25 11:04:08.000000000 
+0200
+++ python-urllib3-1.26.12/debian/gbp.conf      2024-12-21 15:28:17.000000000 
+0100
@@ -1,2 +1,2 @@
 [DEFAULT]
-debian-branch=debian/master
+debian-branch=debian/bookworm
diff -Nru 
python-urllib3-1.26.12/debian/patches/01_do-not-use-embedded-python-six.patch 
python-urllib3-1.26.12/debian/patches/01_do-not-use-embedded-python-six.patch
--- 
python-urllib3-1.26.12/debian/patches/01_do-not-use-embedded-python-six.patch   
    2022-09-22 23:14:14.000000000 +0200
+++ 
python-urllib3-1.26.12/debian/patches/01_do-not-use-embedded-python-six.patch   
    2024-12-21 15:28:17.000000000 +0100
@@ -26,11 +26,12 @@
  src/urllib3/util/response.py                     | 2 +-
  src/urllib3/util/retry.py                        | 2 +-
  src/urllib3/util/ssl_.py                         | 2 +-
+ src/urllib3/util/ssltransport.py                 | 2 +-
  src/urllib3/util/url.py                          | 2 +-
  test/__init__.py                                 | 2 +-
  test/test_collections.py                         | 2 +-
  test/test_compatibility.py                       | 2 +-
- test/test_connectionpool.py                      | 7 ++++---
+ test/test_connectionpool.py                      | 6 +++---
  test/test_fields.py                              | 2 +-
  test/test_filepost.py                            | 2 +-
  test/test_queue_monkeypatch.py                   | 2 +-
@@ -41,7 +42,7 @@
  test/with_dummyserver/test_connectionpool.py     | 4 ++--
  test/with_dummyserver/test_https.py              | 2 +-
  test/with_dummyserver/test_socketlevel.py        | 2 +-
- 35 files changed, 53 insertions(+), 50 deletions(-)
+ 36 files changed, 53 insertions(+), 51 deletions(-)
 
 diff --git a/dummyserver/handlers.py b/dummyserver/handlers.py
 index c90c2fc..f8bdf25 100644
@@ -339,6 +340,19 @@
  from .url import BRACELESS_IPV6_ADDRZ_RE, IPV4_RE
  
  SSLContext = None
+diff --git a/src/urllib3/util/ssltransport.py 
b/src/urllib3/util/ssltransport.py
+index 4a7105d..eaa2b60 100644
+--- a/src/urllib3/util/ssltransport.py
++++ b/src/urllib3/util/ssltransport.py
+@@ -3,7 +3,7 @@ import socket
+ import ssl
+ 
+ from ..exceptions import ProxySchemeUnsupported
+-from ..packages import six
++import six
+ 
+ SSL_BLOCKSIZE = 16384
+ 
 diff --git a/src/urllib3/util/url.py b/src/urllib3/util/url.py
 index b667c16..515d6fc 100644
 --- a/src/urllib3/util/url.py
@@ -392,7 +406,7 @@
  
  
 diff --git a/test/test_connectionpool.py b/test/test_connectionpool.py
-index 872d01c..3a9fb9d 100644
+index 872d01c..ad70c45 100644
 --- a/test/test_connectionpool.py
 +++ b/test/test_connectionpool.py
 @@ -7,6 +7,9 @@ from test import SHORT_TIMEOUT
@@ -405,14 +419,13 @@
  
  from dummyserver.server import DEFAULT_CA
  from urllib3._collections import HTTPHeaderDict
-@@ -26,9 +29,7 @@ from urllib3.exceptions import (
+@@ -26,9 +29,6 @@ from urllib3.exceptions import (
      SSLError,
      TimeoutError,
  )
 -from urllib3.packages.six.moves import http_client as httplib
 -from urllib3.packages.six.moves.http_client import HTTPException
 -from urllib3.packages.six.moves.queue import Empty
-+from urllib3.packages.ssl_match_hostname import CertificateError
  from urllib3.response import HTTPResponse
  from urllib3.util.ssl_match_hostname import CertificateError
  from urllib3.util.timeout import Timeout
diff -Nru python-urllib3-1.26.12/debian/patches/CVE-2023-43804.patch 
python-urllib3-1.26.12/debian/patches/CVE-2023-43804.patch
--- python-urllib3-1.26.12/debian/patches/CVE-2023-43804.patch  1970-01-01 
01:00:00.000000000 +0100
+++ python-urllib3-1.26.12/debian/patches/CVE-2023-43804.patch  2024-12-21 
15:28:17.000000000 +0100
@@ -0,0 +1,157 @@
+From: Seth Michael Larson <sethmichaellar...@gmail.com>
+Date: Mon, 2 Oct 2023 11:43:46 -0500
+Subject: Backport GHSA-v845-jxx5-vc9f
+
+Co-authored-by: Quentin Pradet <quentin.pra...@gmail.com>
+Co-authored-by: Illia Volochii <illia.voloc...@gmail.com>
+Origin: 
https://github.com/urllib3/urllib3/commit/01220354d389cd05474713f8c982d05c9b17aafb
+Bug: https://github.com/urllib3/urllib3/security/advisories/GHSA-v845-jxx5-vc9f
+Bug: https://github.com/urllib3/urllib3/pull/3139
+Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2023-43804
+Bug-Debian: https://bugs.debian.org/1053626
+---
+ src/urllib3/util/retry.py                 |  2 +-
+ test/test_retry.py                        |  4 ++--
+ test/test_retry_deprecated.py             |  2 +-
+ test/with_dummyserver/test_poolmanager.py | 24 +++++++++++++++++++-----
+ 4 files changed, 23 insertions(+), 9 deletions(-)
+
+diff --git a/src/urllib3/util/retry.py b/src/urllib3/util/retry.py
+index 4473a8e..8caad44 100644
+--- a/src/urllib3/util/retry.py
++++ b/src/urllib3/util/retry.py
+@@ -235,7 +235,7 @@ class Retry(object):
+     RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503])
+ 
+     #: Default headers to be used for ``remove_headers_on_redirect``
+-    DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Authorization"])
++    DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Cookie", 
"Authorization"])
+ 
+     #: Maximum backoff time.
+     DEFAULT_BACKOFF_MAX = 120
+diff --git a/test/test_retry.py b/test/test_retry.py
+index 53f0935..7297aa5 100644
+--- a/test/test_retry.py
++++ b/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):
+diff --git a/test/test_retry_deprecated.py b/test/test_retry_deprecated.py
+index 4b3c9d8..30acfce 100644
+--- a/test/test_retry_deprecated.py
++++ b/test/test_retry_deprecated.py
+@@ -295,7 +295,7 @@ 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"])
+diff --git a/test/with_dummyserver/test_poolmanager.py 
b/test/with_dummyserver/test_poolmanager.py
+index fa07a37..02a3811 100644
+--- a/test/with_dummyserver/test_poolmanager.py
++++ b/test/with_dummyserver/test_poolmanager.py
+@@ -141,7 +141,7 @@ class TestPoolManager(HTTPDummyServerTestCase):
+                 "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(HTTPDummyServerTestCase):
+             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(HTTPDummyServerTestCase):
+ 
+             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(HTTPDummyServerTestCase):
+                 "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(HTTPDummyServerTestCase):
+             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(HTTPDummyServerTestCase):
+                 "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(HTTPDummyServerTestCase):
+ 
+             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(HTTPDummyServerTestCase):
+             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_redirect_without_preload_releases_connection(self):
+         with PoolManager(block=True, maxsize=2) as http:
diff -Nru python-urllib3-1.26.12/debian/patches/CVE-2023-45803.patch 
python-urllib3-1.26.12/debian/patches/CVE-2023-45803.patch
--- python-urllib3-1.26.12/debian/patches/CVE-2023-45803.patch  1970-01-01 
01:00:00.000000000 +0100
+++ python-urllib3-1.26.12/debian/patches/CVE-2023-45803.patch  2024-12-21 
15:28:17.000000000 +0100
@@ -0,0 +1,177 @@
+From: Illia Volochii <illia.voloc...@gmail.com>
+Date: Tue, 17 Oct 2023 19:35:39 +0300
+Subject: Merge pull request from GHSA-g4mx-q9vg-27p4
+
+Origin: 
https://github.com/urllib3/urllib3/commit/b594c5ceaca38e1ac215f916538fb128e3526a36
+Bug: https://github.com/urllib3/urllib3/security/advisories/GHSA-g4mx-q9vg-27p4
+Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2023-45803
+Bug-Debian: https://bugs.debian.org/1054226
+---
+ 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(-)
+
+diff --git a/dummyserver/handlers.py b/dummyserver/handlers.py
+index f8bdf25..7d3e413 100644
+--- a/dummyserver/handlers.py
++++ b/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
+ 
+diff --git a/src/urllib3/_collections.py b/src/urllib3/_collections.py
+index 527c1fe..6bc6e2c 100644
+--- a/src/urllib3/_collections.py
++++ b/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
+diff --git a/src/urllib3/connectionpool.py b/src/urllib3/connectionpool.py
+index 2d50f3f..06aa8b8 100644
+--- a/src/urllib3/connectionpool.py
++++ b/src/urllib3/connectionpool.py
+@@ -12,6 +12,7 @@ from socket import timeout as SocketTimeout
+ import six
+ from six.moves import queue
+ 
++from ._collections import HTTPHeaderDict
+ from .connection import (
+     BaseSSLError,
+     BrokenPipeError,
+@@ -833,7 +834,11 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
+         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)
+diff --git a/src/urllib3/poolmanager.py b/src/urllib3/poolmanager.py
+index ca305ec..87467ad 100644
+--- a/src/urllib3/poolmanager.py
++++ b/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, 
port_by_scheme
+ from .exceptions import (
+     LocationValueError,
+@@ -382,9 +382,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):
+diff --git a/test/with_dummyserver/test_connectionpool.py 
b/test/with_dummyserver/test_connectionpool.py
+index 2177c24..7fc0787 100644
+--- a/test/with_dummyserver/test_connectionpool.py
++++ b/test/with_dummyserver/test_connectionpool.py
+@@ -411,6 +411,17 @@ class TestConnectionPool(HTTPDummyServerTestCase):
+             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:
+diff --git a/test/with_dummyserver/test_poolmanager.py 
b/test/with_dummyserver/test_poolmanager.py
+index 02a3811..509daf2 100644
+--- a/test/with_dummyserver/test_poolmanager.py
++++ b/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.connectionpool import port_by_scheme
+ from urllib3.exceptions import MaxRetryError, URLSchemeUnknown
+ from urllib3.poolmanager import PoolManager
+@@ -236,6 +237,20 @@ class TestPoolManager(HTTPDummyServerTestCase):
+             assert r._pool.num_connections == 1
+             assert len(http.pools) == 1
+ 
++    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_unknown_scheme(self):
+         with PoolManager() as http:
+             unknown_scheme = "unknown"
diff -Nru python-urllib3-1.26.12/debian/patches/CVE-2024-37891.patch 
python-urllib3-1.26.12/debian/patches/CVE-2024-37891.patch
--- python-urllib3-1.26.12/debian/patches/CVE-2024-37891.patch  1970-01-01 
01:00:00.000000000 +0100
+++ python-urllib3-1.26.12/debian/patches/CVE-2024-37891.patch  2024-12-21 
15:28:17.000000000 +0100
@@ -0,0 +1,164 @@
+From: Quentin Pradet <quentin.pra...@gmail.com>
+Date: Mon, 17 Jun 2024 11:09:06 +0400
+Subject: Merge pull request from GHSA-34jh-p97f-mpxf
+
+Strip Proxy-Authorization header on redirects
+
+Origin: 
https://github.com/urllib3/urllib3/commit/40b6d1605814dd1db0a46e202d6e56f2e4c9a468
+Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2024-37891
+Bug-Debian: https://bugs.debian.org/1074149
+---
+ src/urllib3/util/retry.py                 |  4 +++-
+ test/test_retry.py                        |  6 +++++-
+ test/test_retry_deprecated.py             |  6 +++++-
+ test/with_dummyserver/test_poolmanager.py | 26 +++++++++++++++++++++++---
+ 4 files changed, 36 insertions(+), 6 deletions(-)
+
+diff --git a/src/urllib3/util/retry.py b/src/urllib3/util/retry.py
+index 8caad44..e00bf4b 100644
+--- a/src/urllib3/util/retry.py
++++ b/src/urllib3/util/retry.py
+@@ -235,7 +235,9 @@ class Retry(object):
+     RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503])
+ 
+     #: Default headers to be used for ``remove_headers_on_redirect``
+-    DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Cookie", 
"Authorization"])
++    DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(
++        ["Cookie", "Authorization", "Proxy-Authorization"]
++    )
+ 
+     #: Maximum backoff time.
+     DEFAULT_BACKOFF_MAX = 120
+diff --git a/test/test_retry.py b/test/test_retry.py
+index 7297aa5..7468322 100644
+--- a/test/test_retry.py
++++ b/test/test_retry.py
+@@ -293,7 +293,11 @@ class TestRetry(object):
+     def test_retry_default_remove_headers_on_redirect(self):
+         retry = Retry()
+ 
+-        assert retry.remove_headers_on_redirect == {"authorization", "cookie"}
++        assert retry.remove_headers_on_redirect == {
++            "authorization",
++            "proxy-authorization",
++            "cookie",
++        }
+ 
+     def test_retry_set_remove_headers_on_redirect(self):
+         retry = Retry(remove_headers_on_redirect=["X-API-Secret"])
+diff --git a/test/test_retry_deprecated.py b/test/test_retry_deprecated.py
+index 30acfce..f10aff5 100644
+--- a/test/test_retry_deprecated.py
++++ b/test/test_retry_deprecated.py
+@@ -295,7 +295,11 @@ class TestRetry(object):
+     def test_retry_default_remove_headers_on_redirect(self):
+         retry = Retry()
+ 
+-        assert retry.remove_headers_on_redirect == {"authorization", "cookie"}
++        assert retry.remove_headers_on_redirect == {
++            "authorization",
++            "proxy-authorization",
++            "cookie",
++        }
+ 
+     def test_retry_set_remove_headers_on_redirect(self):
+         retry = Retry(remove_headers_on_redirect=["X-API-Secret"])
+diff --git a/test/with_dummyserver/test_poolmanager.py 
b/test/with_dummyserver/test_poolmanager.py
+index 509daf2..02e3de5 100644
+--- a/test/with_dummyserver/test_poolmanager.py
++++ b/test/with_dummyserver/test_poolmanager.py
+@@ -142,7 +142,11 @@ class TestPoolManager(HTTPDummyServerTestCase):
+                 "GET",
+                 "%s/redirect" % self.base_url,
+                 fields={"target": "%s/headers" % self.base_url_alt},
+-                headers={"Authorization": "foo", "Cookie": "foo=bar"},
++                headers={
++                    "Authorization": "foo",
++                    "Proxy-Authorization": "bar",
++                    "Cookie": "foo=bar",
++                },
+             )
+ 
+             assert r.status == 200
+@@ -150,13 +154,18 @@ class TestPoolManager(HTTPDummyServerTestCase):
+             data = json.loads(r.data.decode("utf-8"))
+ 
+             assert "Authorization" not in data
++            assert "Proxy-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", "cookie": "foo=bar"},
++                headers={
++                    "authorization": "foo",
++                    "proxy-authorization": "baz",
++                    "cookie": "foo=bar",
++                },
+             )
+ 
+             assert r.status == 200
+@@ -165,6 +174,8 @@ class TestPoolManager(HTTPDummyServerTestCase):
+ 
+             assert "authorization" not in data
+             assert "Authorization" not in data
++            assert "proxy-authorization" not in data
++            assert "Proxy-Authorization" not in data
+             assert "cookie" not in data
+             assert "Cookie" not in data
+ 
+@@ -174,7 +185,11 @@ class TestPoolManager(HTTPDummyServerTestCase):
+                 "GET",
+                 "%s/redirect" % self.base_url,
+                 fields={"target": "%s/headers" % self.base_url_alt},
+-                headers={"Authorization": "foo", "Cookie": "foo=bar"},
++                headers={
++                    "Authorization": "foo",
++                    "Proxy-Authorization": "bar",
++                    "Cookie": "foo=bar",
++                },
+                 retries=Retry(remove_headers_on_redirect=[]),
+             )
+ 
+@@ -183,6 +198,7 @@ class TestPoolManager(HTTPDummyServerTestCase):
+             data = json.loads(r.data.decode("utf-8"))
+ 
+             assert data["Authorization"] == "foo"
++            assert data["Proxy-Authorization"] == "bar"
+             assert data["Cookie"] == "foo=bar"
+ 
+     def test_redirect_cross_host_set_removed_headers(self):
+@@ -194,6 +210,7 @@ class TestPoolManager(HTTPDummyServerTestCase):
+                 headers={
+                     "X-API-Secret": "foo",
+                     "Authorization": "bar",
++                    "Proxy-Authorization": "baz",
+                     "Cookie": "foo=bar",
+                 },
+                 retries=Retry(remove_headers_on_redirect=["X-API-Secret"]),
+@@ -205,6 +222,7 @@ class TestPoolManager(HTTPDummyServerTestCase):
+ 
+             assert "X-API-Secret" not in data
+             assert data["Authorization"] == "bar"
++            assert data["Proxy-Authorization"] == "baz"
+             assert data["Cookie"] == "foo=bar"
+ 
+             r = http.request(
+@@ -213,6 +231,7 @@ class TestPoolManager(HTTPDummyServerTestCase):
+                 fields={"target": "%s/headers" % self.base_url_alt},
+                 headers={
+                     "x-api-secret": "foo",
++                    "proxy-authorization": "baz",
+                     "authorization": "bar",
+                     "cookie": "foo=bar",
+                 },
+@@ -226,6 +245,7 @@ class TestPoolManager(HTTPDummyServerTestCase):
+             assert "x-api-secret" not in data
+             assert "X-API-Secret" not in data
+             assert data["Authorization"] == "bar"
++            assert data["Proxy-Authorization"] == "baz"
+             assert data["Cookie"] == "foo=bar"
+ 
+     def test_redirect_without_preload_releases_connection(self):
diff -Nru python-urllib3-1.26.12/debian/patches/series 
python-urllib3-1.26.12/debian/patches/series
--- python-urllib3-1.26.12/debian/patches/series        2022-08-25 
11:04:08.000000000 +0200
+++ python-urllib3-1.26.12/debian/patches/series        2024-12-21 
15:28:17.000000000 +0100
@@ -1,2 +1,5 @@
 01_do-not-use-embedded-python-six.patch
 02_require-cert-verification.patch
+CVE-2023-43804.patch
+CVE-2023-45803.patch
+CVE-2024-37891.patch
diff -Nru python-urllib3-1.26.12/debian/salsa-ci.yml 
python-urllib3-1.26.12/debian/salsa-ci.yml
--- python-urllib3-1.26.12/debian/salsa-ci.yml  2022-08-25 11:04:08.000000000 
+0200
+++ python-urllib3-1.26.12/debian/salsa-ci.yml  2024-12-21 15:28:17.000000000 
+0100
@@ -1,3 +1,8 @@
 ---
 include:
   - 
https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/recipes/debian.yml
+
+variables:
+  RELEASE: 'bookworm'
+  SALSA_CI_DISABLE_REPROTEST: 1
+  SALSA_CI_DISABLE_LINTIAN: 1

Attachment: signature.asc
Description: PGP signature

Reply via email to