We have some news to share for the request index beta feature. We’ve added more options to sort your requests, counters to the individual filters and documentation for the search functionality. Checkout the blog post for more details.

File CVE-2024-11168-validation-IPv6-addrs.patch of Package python3.42323

Origin: https://opensuse.pkgs.org/15.6/opensuse-sle/python-2.7.18-150000.74.1.x86_64.rpm.html
Reviewed-by: Sylvain Beucler <beuc@debian.org>
Last-Update: 2025-03-07

Additional fixes to pass the test suite:
- Address the general case in addition to the http:// special-case
- Only pass unicode data to ipaddress.ip_address
- Fix py2 package usage: s/urllib.parse/urlparse/

From de677f47ee87a532e1184e218db8930e8cd3eb37 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= <mcepl@cepl.eu>
Date: Wed, 13 Nov 2024 14:46:03 +0100
Subject: [PATCH] [CVE-2024-9287] ensure that bracketed hosts found by urlsplit
 are of IPv6 or IPvFuture format
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Fix urlparse incorrectly retrieves IPv4 and regular name hosts from inside of brackets

Reproducer is

    python3 -c \
    'from urllib.parse import urlparse; print(urlparse("https://user:some]password[@host.com"))'

This command should fail with the error "ValueError: '@host.com'
does not appear to be an IPv4 or IPv6 address". If it doesn’t and produces

    ParseResult(scheme='https', netloc='user:some]password[@host.com',
    path='', params='', query='', fragment='')

it is this bug.

Fixes: bsc#1233307 (CVE-2024-11168)
Fixes: gh#python/cpython#103848
Co-authored-by: JohnJamesUtley <jjutley231@gmail.com>
From-PR: gh#python/cpython!103849
Patch: CVE-2024-11168-validation-IPv6-addrs.patch
---
 Lib/ipaddress.py                                                        |   26 ++++++++++
 Lib/test/test_urlparse.py                                               |   26 ++++++++++
 Lib/urllib/parse.py                                                     |   19 ++++++-
 Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst |    2 
 4 files changed, 72 insertions(+), 1 deletion(-)
 create mode 100644 Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst

Index: Python-3.4.10/Lib/ipaddress.py
===================================================================
--- Python-3.4.10.orig/Lib/ipaddress.py	2025-06-19 22:46:48.982151000 +0200
+++ Python-3.4.10/Lib/ipaddress.py	2025-06-19 22:46:49.107266375 +0200
@@ -1804,6 +1804,26 @@
     def version(self):
         return self._version
 
+    @staticmethod
+    def _split_scope_id(ip_str):
+        """Helper function to parse IPv6 string address with scope id.
+
+        See RFC 4007 for details.
+
+        Args:
+            ip_str: A string, the IPv6 address.
+
+        Returns:
+            (addr, scope_id) tuple.
+
+        """
+        addr, sep, scope_id = ip_str.partition('%')
+        if not sep:
+            scope_id = None
+        elif not scope_id or '%' in scope_id:
+            raise AddressValueError('Invalid IPv6 address: "%r"' % ip_str)
+        return addr, scope_id
+
 
 class IPv6Address(_BaseV6, _BaseAddress):
 
@@ -1833,17 +1853,23 @@
         if isinstance(address, int):
             self._check_int_address(address)
             self._ip = address
+            self._scope_id = None
             return
 
         # Constructing from a packed address
         if isinstance(address, bytes):
             self._check_packed_address(address, 16)
             self._ip = int.from_bytes(address, 'big')
+            self._scope_id = None
             return
 
         # Assume input argument to be string or any object representation
         # which converts into a formatted IP string.
         addr_str = str(address)
+        if '/' in addr_str:
+            raise AddressValueError("Unexpected '/' in %r" % address)
+        addr_str, self._scope_id = self._split_scope_id(addr_str)
+
         self._ip = self._ip_int_from_string(addr_str)
 
     @property
Index: Python-3.4.10/Lib/test/test_urlparse.py
===================================================================
--- Python-3.4.10.orig/Lib/test/test_urlparse.py	2025-06-19 22:46:48.800952130 +0200
+++ Python-3.4.10/Lib/test/test_urlparse.py	2025-06-19 22:48:56.330241168 +0200
@@ -948,6 +948,32 @@
         self.assertEqual(p2.scheme, 'tel')
         self.assertEqual(p2.path, '+31641044153')
 
+    def test_invalid_bracketed_hosts(self):
+        self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[192.0.2.146]/Path?Query')
+        self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[important.com:8000]/Path?Query')
+        self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v123r.IP]/Path?Query')
+        self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v12ae]/Path?Query')
+        self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v.IP]/Path?Query')
+        self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v123.]/Path?Query')
+        self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[v]/Path?Query')
+        self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af::2309::fae7:1234]/Path?Query')
+        self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@[0439:23af:2309::fae7:1234:2342:438e:192.0.2.146]/Path?Query')
+        self.assertRaises(ValueError, urllib.parse.urlsplit, 'Scheme://user@]v6a.ip[/Path')
+
+    def test_splitting_bracketed_hosts(self):
+        p1 = urllib.parse.urlsplit('scheme://user@[v6a.ip]/path?query')
+        self.assertEqual(p1.hostname, 'v6a.ip')
+        self.assertEqual(p1.username, 'user')
+        self.assertEqual(p1.path, '/path')
+        p2 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7%test]/path?query')
+        self.assertEqual(p2.hostname, '0439:23af:2309::fae7%test')
+        self.assertEqual(p2.username, 'user')
+        self.assertEqual(p2.path, '/path')
+        p3 = urllib.parse.urlsplit('scheme://user@[0439:23af:2309::fae7:1234:192.0.2.146%test]/path?query')
+        self.assertEqual(p3.hostname, '0439:23af:2309::fae7:1234:192.0.2.146%test')
+        self.assertEqual(p3.username, 'user')
+        self.assertEqual(p3.path, '/path')
+
     def test_telurl_params(self):
         p1 = urllib.parse.urlparse('tel:123-4;phone-context=+1-650-516')
         self.assertEqual(p1.scheme, 'tel')
Index: Python-3.4.10/Lib/urllib/parse.py
===================================================================
--- Python-3.4.10.orig/Lib/urllib/parse.py	2025-06-19 22:46:48.802386890 +0200
+++ Python-3.4.10/Lib/urllib/parse.py	2025-06-19 22:49:37.415012636 +0200
@@ -30,6 +30,7 @@
 import re
 import sys
 import collections
+import ipaddress
 
 __all__ = ["urlparse", "urlunparse", "urljoin", "urldefrag",
            "urlsplit", "urlunsplit", "urlencode", "parse_qs",
@@ -342,6 +343,17 @@
             raise ValueError("netloc '" + netloc + "' contains invalid " +
                              "characters under NFKC normalization")
 
+# Valid bracketed hosts are defined in
+# https://www.rfc-editor.org/rfc/rfc3986#page-49 and https://url.spec.whatwg.org/
+def _check_bracketed_host(hostname):
+    if hostname.startswith('v'):
+        if not re.match(r"\Av[a-fA-F0-9]+\..+\Z", hostname):
+            raise ValueError("IPvFuture address is invalid")
+    else:
+        ip = ipaddress.ip_address(hostname) # Throws Value Error if not IPv6 or IPv4
+        if isinstance(ip, ipaddress.IPv4Address):
+            raise ValueError("An IPv4 address cannot be in brackets")
+
 def _remove_unsafe_bytes_from_url(url):
     for b in _UNSAFE_URL_BYTES_TO_REMOVE:
         url = url.replace(b, "")
@@ -374,6 +386,9 @@
                 if (('[' in netloc and ']' not in netloc) or
                         (']' in netloc and '[' not in netloc)):
                     raise ValueError("Invalid IPv6 URL")
+                if '[' in netloc and ']' in netloc:
+                    bracketed_host = netloc.partition('[')[2].partition(']')[0]
+                    _check_bracketed_host(bracketed_host)
             if allow_fragments and '#' in url:
                 url, fragment = url.split('#', 1)
             if '?' in url:
@@ -392,12 +407,14 @@
             if not rest or any(c not in '0123456789' for c in rest):
                 # not a port number
                 scheme, url = url[:i].lower(), rest
-
     if url[:2] == '//':
         netloc, url = _splitnetloc(url, 2)
         if (('[' in netloc and ']' not in netloc) or
                 (']' in netloc and '[' not in netloc)):
             raise ValueError("Invalid IPv6 URL")
+        if '[' in netloc and ']' in netloc:
+            bracketed_host = netloc.partition('[')[2].partition(']')[0]
+            _check_bracketed_host(bracketed_host)
     if allow_fragments and '#' in url:
         url, fragment = url.split('#', 1)
     if '?' in url:
Index: Python-3.4.10/Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ Python-3.4.10/Misc/NEWS.d/next/Library/2023-04-26-09-54-25.gh-issue-103848.aDSnpR.rst	2025-06-19 22:46:49.108346618 +0200
@@ -0,0 +1,2 @@
+Add checks to ensure that ``[`` bracketed ``]`` hosts found by
+:func:`urllib.parse.urlsplit` are of IPv6 or IPvFuture format.
openSUSE Build Service is sponsored by