Version in base suite: 3.11.2-6+deb12u5 Base version: python3.11_3.11.2-6+deb12u5 Target version: python3.11_3.11.2-6+deb12u6 Base file: /srv/ftp-master.debian.org/ftp/pool/main/p/python3.11/python3.11_3.11.2-6+deb12u5.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/p/python3.11/python3.11_3.11.2-6+deb12u6.dsc changelog | 8 patches/0001-3.11-gh-105704-Disallow-square-brackets-and-in-domai.patch | 112 ++++++++++ patches/0002-3.11-gh-100884-email-_header_value_parser-don-t-enco.patch | 60 +++++ patches/0003-3.11-gh-118643-Fix-AttributeError-in-the-email-modul.patch | 82 +++++++ patches/series | 3 5 files changed, 265 insertions(+) diff -Nru python3.11-3.11.2/debian/changelog python3.11-3.11.2/debian/changelog --- python3.11-3.11.2/debian/changelog 2024-11-30 21:22:50.000000000 +0000 +++ python3.11-3.11.2/debian/changelog 2025-04-28 14:11:48.000000000 +0000 @@ -1,3 +1,11 @@ +python3.11 (3.11.2-6+deb12u6) bookworm; urgency=medium + + * Non-maintainer upload. + * CVE-2025-0938: urlparse accepted hostname containing [ or ] + * CVE-2025-1795: Don't encode list separators in email headers + + -- Adrian Bunk Mon, 28 Apr 2025 17:11:48 +0300 + python3.11 (3.11.2-6+deb12u5) bookworm; urgency=medium * Non-maintainer upload. diff -Nru python3.11-3.11.2/debian/patches/0001-3.11-gh-105704-Disallow-square-brackets-and-in-domai.patch python3.11-3.11.2/debian/patches/0001-3.11-gh-105704-Disallow-square-brackets-and-in-domai.patch --- python3.11-3.11.2/debian/patches/0001-3.11-gh-105704-Disallow-square-brackets-and-in-domai.patch 1970-01-01 00:00:00.000000000 +0000 +++ python3.11-3.11.2/debian/patches/0001-3.11-gh-105704-Disallow-square-brackets-and-in-domai.patch 2025-04-28 14:11:48.000000000 +0000 @@ -0,0 +1,112 @@ +From 4f13593827072325d77a9a880458b205ab980ad0 Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-islington@users.noreply.github.com> +Date: Wed, 19 Feb 2025 14:13:52 +0100 +Subject: [3.11] gh-105704: Disallow square brackets (`[` and `]`) in domain + names for parsed URLs (GH-129418) (#129528) + +Co-authored-by: Seth Michael Larson +Co-authored-by: Peter Bierma +--- + Lib/test/test_urlparse.py | 37 ++++++++++++++++++++++++++++++++++++- + Lib/urllib/parse.py | 20 ++++++++++++++++++-- + 2 files changed, 54 insertions(+), 3 deletions(-) + +diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py +index 83ea618291e..45cca11da47 100644 +--- a/Lib/test/test_urlparse.py ++++ b/Lib/test/test_urlparse.py +@@ -1103,16 +1103,51 @@ def test_invalid_bracketed_hosts(self): + 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') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip]') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip].suffix') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip]/') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip].suffix/') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip]?') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip].suffix?') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]/') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix/') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]?') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix?') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:a') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:a') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:a1') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:a1') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:1a') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:1a') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[::1].suffix:/') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[::1]:?') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://user@prefix.[v6a.ip]') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://user@[v6a.ip].suffix') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://[v6a.ip') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip]') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://]v6a.ip[') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://]v6a.ip') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip[') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix.[v6a.ip') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip].suffix') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix]v6a.ip[suffix') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://prefix]v6a.ip') ++ self.assertRaises(ValueError, urllib.parse.urlsplit, 'scheme://v6a.ip[suffix') + + def test_splitting_bracketed_hosts(self): +- p1 = urllib.parse.urlsplit('scheme://user@[v6a.ip]/path?query') ++ p1 = urllib.parse.urlsplit('scheme://user@[v6a.ip]:1234/path?query') + self.assertEqual(p1.hostname, 'v6a.ip') + self.assertEqual(p1.username, 'user') + self.assertEqual(p1.path, '/path') ++ self.assertEqual(p1.port, 1234) + 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') ++ self.assertIs(p2.port, None) + 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') +diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py +index e5f0b784bf6..5233020a9f0 100644 +--- a/Lib/urllib/parse.py ++++ b/Lib/urllib/parse.py +@@ -436,6 +436,23 @@ def _checknetloc(netloc): + raise ValueError("netloc '" + netloc + "' contains invalid " + + "characters under NFKC normalization") + ++def _check_bracketed_netloc(netloc): ++ # Note that this function must mirror the splitting ++ # done in NetlocResultMixins._hostinfo(). ++ hostname_and_port = netloc.rpartition('@')[2] ++ before_bracket, have_open_br, bracketed = hostname_and_port.partition('[') ++ if have_open_br: ++ # No data is allowed before a bracket. ++ if before_bracket: ++ raise ValueError("Invalid IPv6 URL") ++ hostname, _, port = bracketed.partition(']') ++ # No data is allowed after the bracket but before the port delimiter. ++ if port and not port.startswith(":"): ++ raise ValueError("Invalid IPv6 URL") ++ else: ++ hostname, _, port = hostname_and_port.partition(':') ++ _check_bracketed_host(hostname) ++ + # 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): +@@ -496,8 +513,7 @@ def urlsplit(url, scheme='', allow_fragments=True): + (']' 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) ++ _check_bracketed_netloc(netloc) + if allow_fragments and '#' in url: + url, fragment = url.split('#', 1) + if '?' in url: +-- +2.30.2 + diff -Nru python3.11-3.11.2/debian/patches/0002-3.11-gh-100884-email-_header_value_parser-don-t-enco.patch python3.11-3.11.2/debian/patches/0002-3.11-gh-100884-email-_header_value_parser-don-t-enco.patch --- python3.11-3.11.2/debian/patches/0002-3.11-gh-100884-email-_header_value_parser-don-t-enco.patch 1970-01-01 00:00:00.000000000 +0000 +++ python3.11-3.11.2/debian/patches/0002-3.11-gh-100884-email-_header_value_parser-don-t-enco.patch 2025-04-28 14:11:21.000000000 +0000 @@ -0,0 +1,60 @@ +From b85561b1141471dcef77fc0f76d03736f9da8b92 Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-islington@users.noreply.github.com> +Date: Sat, 17 Feb 2024 14:01:02 +0100 +Subject: [3.11] gh-100884: email/_header_value_parser: don't encode list + separators (GH-100885) (GH-115593) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +ListSeparator should not be encoded. This could happen when a long line +pushes its separator to the next line, which would have been encoded. +(cherry picked from commit 09fab93c3d857496c0bd162797fab816c311ee48) + +Co-authored-by: Thomas Weißschuh +--- + Lib/email/_header_value_parser.py | 3 ++- + Lib/test/test_email/test__header_value_parser.py | 5 +++++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py +index e1b99d5b417..87c4ae9f167 100644 +--- a/Lib/email/_header_value_parser.py ++++ b/Lib/email/_header_value_parser.py +@@ -951,6 +951,7 @@ class _InvalidEwError(errors.HeaderParseError): + # up other parse trees. Maybe should have tests for that, too. + DOT = ValueTerminal('.', 'dot') + ListSeparator = ValueTerminal(',', 'list-separator') ++ListSeparator.as_ew_allowed = False + RouteComponentMarker = ValueTerminal('@', 'route-component-marker') + + # +@@ -2024,7 +2025,7 @@ def get_address_list(value): + address_list.defects.append(errors.InvalidHeaderDefect( + "invalid address in address-list")) + if value: # Must be a , at this point. +- address_list.append(ValueTerminal(',', 'list-separator')) ++ address_list.append(ListSeparator) + value = value[1:] + return address_list, value + +diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py +index 854f2ff009c..7063ce7d71c 100644 +--- a/Lib/test/test_email/test__header_value_parser.py ++++ b/Lib/test/test_email/test__header_value_parser.py +@@ -2946,6 +2946,11 @@ def test_address_list_with_unicode_names_in_quotes(self): + '=?utf-8?q?H=C3=BCbsch?= Kaktus ,\n' + ' =?utf-8?q?bei=C3=9Ft_bei=C3=9Ft?= \n') + ++ def test_address_list_with_list_separator_after_fold(self): ++ to = '0123456789' * 8 + '@foo, ä ' ++ self._test(parser.get_address_list(to)[0], ++ '0123456789' * 8 + '@foo,\n =?utf-8?q?=C3=A4?= \n') ++ + # XXX Need tests with comments on various sides of a unicode token, + # and with unicode tokens in the comments. Spaces inside the quotes + # currently don't do the right thing. +-- +2.30.2 + diff -Nru python3.11-3.11.2/debian/patches/0003-3.11-gh-118643-Fix-AttributeError-in-the-email-modul.patch python3.11-3.11.2/debian/patches/0003-3.11-gh-118643-Fix-AttributeError-in-the-email-modul.patch --- python3.11-3.11.2/debian/patches/0003-3.11-gh-118643-Fix-AttributeError-in-the-email-modul.patch 1970-01-01 00:00:00.000000000 +0000 +++ python3.11-3.11.2/debian/patches/0003-3.11-gh-118643-Fix-AttributeError-in-the-email-modul.patch 2025-04-28 14:11:21.000000000 +0000 @@ -0,0 +1,82 @@ +From c9b1142da7f477f84c7d7b9324cc4883cb8a9be4 Mon Sep 17 00:00:00 2001 +From: Serhiy Storchaka +Date: Thu, 23 May 2024 15:09:03 +0300 +Subject: [3.11] gh-118643: Fix AttributeError in the email module (GH-119099) + (#119393) + +Fix regression introduced in gh-100884: AttributeError when re-fold a long +address list. + +Also fix more cases of incorrect encoding of the address separator in the +address list missed in gh-100884. +(cherry picked from commit 858b9e85fcdd495947c9e892ce6e3734652c48f2) +--- + Lib/email/_header_value_parser.py | 16 +++++++++++++--- + Lib/test/test_email/test__header_value_parser.py | 12 ++++++++++-- + 2 files changed, 23 insertions(+), 5 deletions(-) + +diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py +index 87c4ae9f167..04dbfa2ee86 100644 +--- a/Lib/email/_header_value_parser.py ++++ b/Lib/email/_header_value_parser.py +@@ -952,6 +952,7 @@ class _InvalidEwError(errors.HeaderParseError): + DOT = ValueTerminal('.', 'dot') + ListSeparator = ValueTerminal(',', 'list-separator') + ListSeparator.as_ew_allowed = False ++ListSeparator.syntactic_break = False + RouteComponentMarker = ValueTerminal('@', 'route-component-marker') + + # +@@ -2826,13 +2827,22 @@ def _refold_parse_tree(parse_tree, *, policy): + if not hasattr(part, 'encode'): + # It's not a Terminal, do each piece individually. + parts = list(part) + parts +- else: ++ want_encoding = False ++ continue ++ elif part.as_ew_allowed: + # It's a terminal, wrap it as an encoded word, possibly + # combining it with previously encoded words if allowed. + last_ew = _fold_as_ew(tstr, lines, maxlen, last_ew, + part.ew_combine_allowed, charset) +- want_encoding = False +- continue ++ want_encoding = False ++ continue ++ else: ++ # It's a terminal which should be kept non-encoded ++ # (e.g. a ListSeparator). ++ last_ew = None ++ want_encoding = False ++ # fall through ++ + if len(tstr) <= maxlen - len(lines[-1]): + lines[-1] += tstr + continue +diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py +index 7063ce7d71c..1f575545a11 100644 +--- a/Lib/test/test_email/test__header_value_parser.py ++++ b/Lib/test/test_email/test__header_value_parser.py +@@ -2947,9 +2947,17 @@ def test_address_list_with_unicode_names_in_quotes(self): + ' =?utf-8?q?bei=C3=9Ft_bei=C3=9Ft?= \n') + + def test_address_list_with_list_separator_after_fold(self): +- to = '0123456789' * 8 + '@foo, ä ' ++ a = 'x' * 66 + '@example.com' ++ to = f'{a}, "Hübsch Kaktus" ' + self._test(parser.get_address_list(to)[0], +- '0123456789' * 8 + '@foo,\n =?utf-8?q?=C3=A4?= \n') ++ f'{a},\n =?utf-8?q?H=C3=BCbsch?= Kaktus \n') ++ ++ a = '.' * 79 ++ to = f'"{a}" , "Hübsch Kaktus" ' ++ self._test(parser.get_address_list(to)[0], ++ f'{a}\n' ++ ' , =?utf-8?q?H=C3=BCbsch?= Kaktus ' ++ '\n') + + # XXX Need tests with comments on various sides of a unicode token, + # and with unicode tokens in the comments. Spaces inside the quotes +-- +2.30.2 + diff -Nru python3.11-3.11.2/debian/patches/series python3.11-3.11.2/debian/patches/series --- python3.11-3.11.2/debian/patches/series 2024-11-30 21:22:50.000000000 +0000 +++ python3.11-3.11.2/debian/patches/series 2025-04-28 14:11:48.000000000 +0000 @@ -58,3 +58,6 @@ 0003-3.11-gh-123067-Fix-quadratic-complexity-in-parsing-q.patch 0004-3.11-gh-124651-Quote-template-strings-in-venv-activa.patch 0005-3.11-gh-103848-Adds-checks-to-ensure-that-bracketed-.patch +0001-3.11-gh-105704-Disallow-square-brackets-and-in-domai.patch +0002-3.11-gh-100884-email-_header_value_parser-don-t-enco.patch +0003-3.11-gh-118643-Fix-AttributeError-in-the-email-modul.patch