Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-urllib3_1 for 
openSUSE:Factory checked in at 2025-06-27 23:00:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-urllib3_1 (Old)
 and      /work/SRC/openSUSE:Factory/.python-urllib3_1.new.7067 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-urllib3_1"

Fri Jun 27 23:00:42 2025 rev:11 rq:1288435 version:1.26.20

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-urllib3_1/python-urllib3_1.changes        
2025-05-23 14:27:32.976952342 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-urllib3_1.new.7067/python-urllib3_1.changes  
    2025-06-27 23:01:39.962147900 +0200
@@ -1,0 +2,7 @@
+Wed Jun 25 05:18:37 UTC 2025 - Steve Kowalik <steven.kowa...@suse.com>
+
+- Add patch CVE-2025-50181-poolmanager-redirects.patch:
+  * Pool managers now properly control redirects when retries is passed
+    (CVE-2025-50181, GHSA-pq67-6m6q-mj2v, bsc#1244925)
+
+-------------------------------------------------------------------

New:
----
  CVE-2025-50181-poolmanager-redirects.patch

----------(New B)----------
  New:
- Add patch CVE-2025-50181-poolmanager-redirects.patch:
  * Pool managers now properly control redirects when retries is passed
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-urllib3_1.spec ++++++
--- /var/tmp/diff_new_pack.WbBrxC/_old  2025-06-27 23:01:40.538171640 +0200
+++ /var/tmp/diff_new_pack.WbBrxC/_new  2025-06-27 23:01:40.538171640 +0200
@@ -35,6 +35,8 @@
 # PATCH-FIX-UPSTREAM remove_mock.patch gh#urllib3/urllib3#2108 mc...@suse.com
 # remove dependency on the external module mock
 Patch0:         remove_mock.patch
+# PATCH-FIX-UPSTREAM CVE-2025-50181 gh#urllib3/urllib3@f05b1329126d, 
bsc#1244925
+Patch1:         CVE-2025-50181-poolmanager-redirects.patch
 BuildRequires:  %{python_module base >= 3.7}
 BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module setuptools}

++++++ CVE-2025-50181-poolmanager-redirects.patch ++++++
>From f05b1329126d5be6de501f9d1e3e36738bc08857 Mon Sep 17 00:00:00 2001
From: Illia Volochii <illia.voloc...@gmail.com>
Date: Wed, 18 Jun 2025 16:25:01 +0300
Subject: [PATCH] Merge commit from fork

* Apply Quentin's suggestion

Co-authored-by: Quentin Pradet <quentin.pra...@gmail.com>

* Add tests for disabled redirects in the pool manager

* Add a possible fix for the issue with not raised `MaxRetryError`

* Make urllib3 handle redirects instead of JS when JSPI is used

* Fix info in the new comment

* State that redirects with XHR are not controlled by urllib3

* Remove excessive params from new test requests

* Add tests reaching max non-0 redirects

* Test redirects with Emscripten

* Fix `test_merge_pool_kwargs`

* Add a changelog entry

* Parametrize tests

* Drop a fix for Emscripten

* Apply Seth's suggestion to docs

Co-authored-by: Seth Michael Larson <sethmichaellar...@gmail.com>

* Use a minor release instead of the patch one

---------

Co-authored-by: Quentin Pradet <quentin.pra...@gmail.com>
Co-authored-by: Seth Michael Larson <sethmichaellar...@gmail.com>
---
 CHANGES.rst                                |   9 ++
 docs/reference/contrib/emscripten.rst      |   2 +-
 dummyserver/app.py                         |   1 +
 src/urllib3/poolmanager.py                 |  18 +++-
 test/contrib/emscripten/test_emscripten.py |  16 ++++
 test/test_poolmanager.py                   |   5 +-
 test/with_dummyserver/test_poolmanager.py  | 101 +++++++++++++++++++++
 7 files changed, 148 insertions(+), 4 deletions(-)

Index: urllib3-1.26.20/src/urllib3/poolmanager.py
===================================================================
--- urllib3-1.26.20.orig/src/urllib3/poolmanager.py
+++ urllib3-1.26.20/src/urllib3/poolmanager.py
@@ -170,6 +170,22 @@ class PoolManager(RequestMethods):
 
     def __init__(self, num_pools=10, headers=None, **connection_pool_kw):
         RequestMethods.__init__(self, headers)
+        if "retries" in connection_pool_kw:
+            retries = connection_pool_kw["retries"]
+            if not isinstance(retries, Retry):
+                # When Retry is initialized, raise_on_redirect is based
+                # on a redirect boolean value.
+                # But requests made via a pool manager always set
+                # redirect to False, and raise_on_redirect always ends
+                # up being False consequently.
+                # Here we fix the issue by setting raise_on_redirect to
+                # a value needed by the pool manager without considering
+                # the redirect boolean.
+                raise_on_redirect = retries is not False
+                retries = Retry.from_int(retries, redirect=False)
+                retries.raise_on_redirect = raise_on_redirect
+                connection_pool_kw = connection_pool_kw.copy()
+                connection_pool_kw["retries"] = retries
         self.connection_pool_kw = connection_pool_kw
         self.pools = RecentlyUsedContainer(num_pools)
 
@@ -389,7 +405,7 @@ class PoolManager(RequestMethods):
             kw["body"] = None
             kw["headers"] = 
HTTPHeaderDict(kw["headers"])._prepare_for_method_change()
 
-        retries = kw.get("retries")
+        retries = kw.get("retries", response.retries)
         if not isinstance(retries, Retry):
             retries = Retry.from_int(retries, redirect=redirect)
 
Index: urllib3-1.26.20/test/test_poolmanager.py
===================================================================
--- urllib3-1.26.20.orig/test/test_poolmanager.py
+++ urllib3-1.26.20/test/test_poolmanager.py
@@ -326,9 +326,10 @@ class TestPoolManager(object):
 
     def test_merge_pool_kwargs(self):
         """Assert _merge_pool_kwargs works in the happy case"""
-        p = PoolManager(strict=True)
+        retries = retry.Retry(total=100)
+        p = PoolManager(strict=True, retries=retries)
         merged = p._merge_pool_kwargs({"new_key": "value"})
-        assert {"strict": True, "new_key": "value"} == merged
+        assert {"retries": retries, "strict": True, "new_key": "value"} == 
merged
 
     def test_merge_pool_kwargs_none(self):
         """Assert false-y values to _merge_pool_kwargs result in defaults"""
Index: urllib3-1.26.20/test/with_dummyserver/test_poolmanager.py
===================================================================
--- urllib3-1.26.20.orig/test/with_dummyserver/test_poolmanager.py
+++ urllib3-1.26.20/test/with_dummyserver/test_poolmanager.py
@@ -82,6 +82,94 @@ class TestPoolManager(HTTPDummyServerTes
             assert r.status == 200
             assert r.data == b"Dummy server!"
 
+    @pytest.mark.parametrize(
+        "retries",
+        (0, Retry(total=0), Retry(redirect=0), Retry(total=0, redirect=0)),
+    )
+    def test_redirects_disabled_for_pool_manager_with_0(
+        self, retries: typing.Literal[0] | Retry
+    ) -> None:
+        """
+        Check handling redirects when retries is set to 0 on the pool
+        manager.
+        """
+        with PoolManager(retries=retries) as http:
+            with pytest.raises(MaxRetryError):
+                http.request("GET", f"{self.base_url}/redirect")
+
+            # Setting redirect=True should not change the behavior.
+            with pytest.raises(MaxRetryError):
+                http.request("GET", f"{self.base_url}/redirect", redirect=True)
+
+            # Setting redirect=False should not make it follow the redirect,
+            # but MaxRetryError should not be raised.
+            response = http.request("GET", f"{self.base_url}/redirect", 
redirect=False)
+            assert response.status == 303
+
+    @pytest.mark.parametrize(
+        "retries",
+        (
+            False,
+            Retry(total=False),
+            Retry(redirect=False),
+            Retry(total=False, redirect=False),
+        ),
+    )
+    def test_redirects_disabled_for_pool_manager_with_false(
+        self, retries: typing.Literal[False] | Retry
+    ) -> None:
+        """
+        Check that setting retries set to False on the pool manager disables
+        raising MaxRetryError and redirect=True does not change the
+        behavior.
+        """
+        with PoolManager(retries=retries) as http:
+            response = http.request("GET", f"{self.base_url}/redirect")
+            assert response.status == 303
+
+            response = http.request("GET", f"{self.base_url}/redirect", 
redirect=True)
+            assert response.status == 303
+
+            response = http.request("GET", f"{self.base_url}/redirect", 
redirect=False)
+            assert response.status == 303
+
+    def test_redirects_disabled_for_individual_request(self) -> None:
+        """
+        Check handling redirects when they are meant to be disabled
+        on the request level.
+        """
+        with PoolManager() as http:
+            # Check when redirect is not passed.
+            with pytest.raises(MaxRetryError):
+                http.request("GET", f"{self.base_url}/redirect", retries=0)
+            response = http.request("GET", f"{self.base_url}/redirect", 
retries=False)
+            assert response.status == 303
+
+            # Check when redirect=True.
+            with pytest.raises(MaxRetryError):
+                http.request(
+                    "GET", f"{self.base_url}/redirect", retries=0, 
redirect=True
+                )
+            response = http.request(
+                "GET", f"{self.base_url}/redirect", retries=False, 
redirect=True
+            )
+            assert response.status == 303
+
+            # Check when redirect=False.
+            response = http.request(
+                "GET", f"{self.base_url}/redirect", retries=0, redirect=False
+            )
+            assert response.status == 303
+            response = http.request(
+                "GET", f"{self.base_url}/redirect", retries=False, 
redirect=False
+            )
+            assert response.status == 303
+
+
+     def test_redirect_cross_host_remove_headers(self) -> None:
+         with PoolManager() as http:
+             r = http.request(
+
     def test_cross_host_redirect(self):
         with PoolManager() as http:
             cross_host_location = "%s/echo?a=b" % self.base_url_alt
@@ -136,6 +224,24 @@ class TestPoolManager(HTTPDummyServerTes
             pool = http.connection_from_host(self.host, self.port)
             assert pool.num_connections == 1
 
+        # Check when retries are configured for the pool manager.
+        with PoolManager(retries=1) as http:
+            with pytest.raises(MaxRetryError):
+                http.request(
+                    "GET",
+                    f"{self.base_url}/redirect",
+                    fields={"target": f"/redirect?target={self.base_url}/"},
+                )
+
+            # Here we allow more retries for the request.
+            response = http.request(
+                "GET",
+                f"{self.base_url}/redirect",
+                fields={"target": f"/redirect?target={self.base_url}/"},
+                retries=2,
+            )
+            assert response.status == 200
+
     def test_redirect_cross_host_remove_headers(self):
         with PoolManager() as http:
             r = http.request(

Reply via email to