Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python312 for openSUSE:Factory checked in at 2026-02-18 17:04:55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python312 (Old) and /work/SRC/openSUSE:Factory/.python312.new.1977 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python312" Wed Feb 18 17:04:55 2026 rev:43 rq:1332782 version:3.12.12 Changes: -------- --- /work/SRC/openSUSE:Factory/python312/python312.changes 2025-12-29 15:15:46.188461740 +0100 +++ /work/SRC/openSUSE:Factory/.python312.new.1977/python312.changes 2026-02-18 17:05:18.261410406 +0100 @@ -1,0 +2,26 @@ +Fri Feb 6 00:07:20 CET 2026 - Matej Cepl <[email protected]> + +- CVE-2025-11468: to preserve parens when folding comments. + (bsc#1257029, gh#python/cpython#143935) + CVE-2025-11468-email-hdr-fold-comment.patch +- CVE-2025-12781: fix decoding with non-standard Base64 alphabet + (bsc#1257108, gh#python/cpython#125346) + CVE-2025-12781-b64decode-alt-chars.patch +- CVE-2026-0672: rejects control characters in http cookies. + (bsc#1257031, gh#python/cpython#143919) + CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch +- CVE-2026-0865: rejecting control characters in + wsgiref.headers.Headers, which could be abused for injecting + false HTTP headers. (bsc#1257042, gh#python/cpython#143916) + CVE-2026-0865-wsgiref-ctrl-chars.patch +- CVE-2025-15366: basically the same as the previous patch for + IMAP protocol. (bsc#1257044, gh#python/cpython#143921) + CVE-2025-15366-imap-ctrl-chars.patch +- CVE-2025-15282: basically the same as the previous patch for + urllib library. (bsc#1257046, gh#python/cpython#143925) + CVE-2025-15282-urllib-ctrl-chars.patch +- CVE-2025-15367: basically the same as the previous patch for + poplib library. (bsc#1257041, gh#python/cpython#143923) + CVE-2025-15367-poplib-ctrl-chars.patch + +------------------------------------------------------------------- @@ -4,2 +30 @@ -- Add CVE-2025-13836-http-resp-cont-len.patch (bsc#1254400, - CVE-2025-13836) to prevent reading an HTTP response from +- CVE-2025-13836: to prevent reading an HTTP response from @@ -7,7 +32,9 @@ - Content-Length per default as the length. -- Add CVE-2025-12084-minidom-quad-search.patch prevent quadratic - behavior in node ID cache clearing (CVE-2025-12084, - bsc#1254997). -- Add CVE-2025-13837-plistlib-mailicious-length.patch protect - against OOM when loading malicious content (CVE-2025-13837, - bsc#1254401). + Content-Length per default as the length. (bsc#1254400, + gh#python/cpython#119451) + CVE-2025-13836-http-resp-cont-len.patch +- CVE-2025-12084: prevent quadratic behavior in node ID cache + clearing. (bsc#1254997, gh#python/cpython#142145) + CVE-2025-12084-minidom-quad-search.patch +- CVE-2025-13837: protect against OOM when loading malicious + content. (bsc#1254401, gh#python/cpython#119342) + CVE-2025-13837-plistlib-mailicious-length.patch @@ -1211,4 +1238,4 @@ - - gh-99242: os.getloadavg() may throw OSError when - running regression tests under certain conditions (e.g. - chroot). This error is now caught and ignored, since - reporting load average is optional. + - gh-99242: os.getloadavg() may throw OSError when running + regression tests under certain conditions (e.g. chroot). + This error is now caught and ignored, since reporting load + average is optional. @@ -1219,11 +1246,9 @@ - - gh-121160: Add a test for - readline.set_history_length(). Note that this test may fail - on readline libraries. - - gh-121200: Fix test_expanduser_pwd2() of - test_posixpath. Call getpwnam() to get pw_dir, since it - can be different than getpwall() pw_dir. Patch by Victor - Stinner. - - gh-121188: When creating the JUnit XML file, regrtest - now escapes characters which are invalid in XML, such - as the chr(27) control character used in ANSI escape - sequences. Patch by Victor Stinner. + - gh-121160: Add a test for readline.set_history_length(). + Note that this test may fail on readline libraries. + - gh-121200: Fix test_expanduser_pwd2() of test_posixpath. + Call getpwnam() to get pw_dir, since it can be different + than getpwall() pw_dir. Patch by Victor Stinner. + - gh-121188: When creating the JUnit XML file, regrtest now + escapes characters which are invalid in XML, such as the + chr(27) control character used in ANSI escape sequences. + Patch by Victor Stinner. @@ -1252,6 +1277,6 @@ - - gh-121650: email headers with embedded newlines are - now quoted on output. The generator will now refuse to - serialize (write) headers that are unsafely folded or - delimited; see verify_generated_headers. (Contributed by - Bas Bloemsaat and Petr Viktorin in gh-121650; bsc#1228780, - CVE-2024-6923). + - CVE-2026-1299 and CVE-2024-6923: email headers with + embedded newlines are now quoted on output. The generator + will now refuse to serialize (write) headers that are + unsafely folded or delimited; see verify_generated_headers. + (Contributed by Bas Bloemsaat and Petr Viktorin in + bsc#1228780, gh-121650; bsc#1257181, gh-121650). @@ -1294,2 +1319,2 @@ - - gh-120495: Fix incorrect exception handling in Tab - Nanny. Patch by Wulian233. + - gh-120495: Fix incorrect exception handling in Tab Nanny. + Patch by Wulian233. @@ -1304,3 +1329,3 @@ - would produce incorrect results if type parameters in a - class scope were overridden by assignments in a class scope - and from __future__ import annotations semantics were + would produce incorrect results if type parameters in + a class scope were overridden by assignments in a class + scope and from __future__ import annotations semantics were @@ -1331,5 +1356,5 @@ - - gh-81936: help() and showtopic() methods now respect a - configured output argument to pydoc.Helper and not use the - pager in such cases. Patch by Enrico Tröger. - - gh-119577: The DeprecationWarning emitted when testing - the truth value of an xml.etree.ElementTree.Element now + - gh-81936: help() and showtopic() methods now respect + a configured output argument to pydoc.Helper and not use + the pager in such cases. Patch by Enrico Tröger. + - gh-119577: The DeprecationWarning emitted when testing the + truth value of an xml.etree.ElementTree.Element now @@ -1364,2 +1389,2 @@ - - gh-121871: Documentation HTML varies from timestamp. Patch by - Bernhard M. Wiedemann (bsc#1227999). + - gh-121871: Documentation HTML varies from timestamp. Patch + by Bernhard M. Wiedemann (bsc#1227999). @@ -1372,2 +1397,2 @@ - - gh-122029: Emit c_call events in sys.setprofile() when a - PyMethodObject pointing to a PyCFunction is called. + - gh-122029: Emit c_call events in sys.setprofile() when + a PyMethodObject pointing to a PyCFunction is called. @@ -1390,2 +1415,2 @@ - modification of a list object, where one thread assigns a - slice and another clears it. + modification of a list object, where one thread assigns + a slice and another clears it. @@ -1393,2 +1418,2 @@ - bytes and bytearray objects when using protocol version - 5. Patch by Bénédikt Tran. + bytes and bytearray objects when using protocol version 5. + Patch by Bénédikt Tran. New: ---- CVE-2025-11468-email-hdr-fold-comment.patch CVE-2025-12781-b64decode-alt-chars.patch CVE-2025-15282-urllib-ctrl-chars.patch CVE-2025-15366-imap-ctrl-chars.patch CVE-2025-15367-poplib-ctrl-chars.patch CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch CVE-2026-0865-wsgiref-ctrl-chars.patch ----------(New B)---------- New: (bsc#1257029, gh#python/cpython#143935) CVE-2025-11468-email-hdr-fold-comment.patch - CVE-2025-12781: fix decoding with non-standard Base64 alphabet New: (bsc#1257108, gh#python/cpython#125346) CVE-2025-12781-b64decode-alt-chars.patch - CVE-2026-0672: rejects control characters in http cookies. New: urllib library. (bsc#1257046, gh#python/cpython#143925) CVE-2025-15282-urllib-ctrl-chars.patch - CVE-2025-15367: basically the same as the previous patch for New: IMAP protocol. (bsc#1257044, gh#python/cpython#143921) CVE-2025-15366-imap-ctrl-chars.patch - CVE-2025-15282: basically the same as the previous patch for New: poplib library. (bsc#1257041, gh#python/cpython#143923) CVE-2025-15367-poplib-ctrl-chars.patch New: (bsc#1257031, gh#python/cpython#143919) CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch - CVE-2026-0865: rejecting control characters in New: false HTTP headers. (bsc#1257042, gh#python/cpython#143916) CVE-2026-0865-wsgiref-ctrl-chars.patch - CVE-2025-15366: basically the same as the previous patch for ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python312.spec ++++++ --- /var/tmp/diff_new_pack.vwuuUW/_old 2026-02-18 17:05:21.597549260 +0100 +++ /var/tmp/diff_new_pack.vwuuUW/_new 2026-02-18 17:05:21.601549426 +0100 @@ -204,6 +204,28 @@ # PATCH-FIX-UPSTREAM CVE-2025-13837-plistlib-mailicious-length.patch bsc#1254401 [email protected] # protect against OOM when loading malicious content Patch51: CVE-2025-13837-plistlib-mailicious-length.patch +# PATCH-FIX-UPSTREAM CVE-2025-11468-email-hdr-fold-comment.patch bsc#1257029 [email protected] +# Email preserve parens when folding comments +Patch52: CVE-2025-11468-email-hdr-fold-comment.patch +# PATCH-FIX-UPSTREAM CVE-2025-12781-b64decode-alt-chars.patch bsc#1257108 [email protected] +# Fix decoding with non-standard Base64 alphabet gh#python/cpython#125346 +Patch53: CVE-2025-12781-b64decode-alt-chars.patch +# PATCH-FIX-UPSTREAM CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch bsc#1257031 [email protected] +# Reject control characters in http cookies +Patch54: CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch +# PATCH-FIX-UPSTREAM CVE-2026-0865-wsgiref-ctrl-chars.patch bsc#1257042 [email protected] +# Reject control characters in wsgiref.headers.Headers +Patch55: CVE-2026-0865-wsgiref-ctrl-chars.patch +# PATCH-FIX-UPSTREAM CVE-2025-15366-imap-ctrl-chars.patch bsc#1257044 [email protected] +# Reject control characters in wsgiref.headers.Headers +Patch56: CVE-2025-15366-imap-ctrl-chars.patch +# PATCH-FIX-UPSTREAM CVE-2025-15282-urllib-ctrl-chars.patch bsc#1257046 [email protected] +# Reject control characters in urllib +Patch57: CVE-2025-15282-urllib-ctrl-chars.patch +# PATCH-FIX-UPSTREAM CVE-2025-15367-poplib-ctrl-chars.patch bsc#1257041 [email protected] +# Reject control characters in poplib +Patch58: CVE-2025-15367-poplib-ctrl-chars.patch +### END OF PATCHES BuildRequires: autoconf-archive BuildRequires: automake BuildRequires: fdupes ++++++ CVE-2025-11468-email-hdr-fold-comment.patch ++++++ >From 3900a2cb7d8321629717b8483179263a968bf552 Mon Sep 17 00:00:00 2001 From: Seth Michael Larson <[email protected]> Date: Mon, 19 Jan 2026 06:38:22 -0600 Subject: [PATCH] gh-143935: Email preserve parens when folding comments (GH-143936) Fix a bug in the folding of comments when flattening an email message using a modern email policy. Comments consisting of a very long sequence of non-foldable characters could trigger a forced line wrap that omitted the required leading space on the continuation line, causing the remainder of the comment to be interpreted as a new header field. This enabled header injection with carefully crafted inputs. (cherry picked from commit 17d1490aa97bd6b98a42b1a9b324ead84e7fd8a2) Co-authored-by: Seth Michael Larson <[email protected]> Co-authored-by: Denis Ledoux <[email protected]> --- Lib/email/_header_value_parser.py | 15 ++++++ Lib/test/test_email/test__header_value_parser.py | 23 ++++++++++ Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst | 6 ++ 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst Index: Python-3.12.12/Lib/email/_header_value_parser.py =================================================================== --- Python-3.12.12.orig/Lib/email/_header_value_parser.py 2026-02-06 00:08:35.667684507 +0100 +++ Python-3.12.12/Lib/email/_header_value_parser.py 2026-02-06 00:08:40.746286971 +0100 @@ -101,6 +101,12 @@ return str(value).replace('\\', '\\\\').replace('"', '\\"') +def make_parenthesis_pairs(value): + """Escape parenthesis and backslash for use within a comment.""" + return str(value).replace('\\', '\\\\') \ + .replace('(', '\\(').replace(')', '\\)') + + def quote_string(value): escaped = make_quoted_pairs(value) return f'"{escaped}"' @@ -933,7 +939,7 @@ return ' ' def startswith_fws(self): - return True + return self and self[0] in WSP class ValueTerminal(Terminal): @@ -2922,6 +2928,13 @@ [ValueTerminal(make_quoted_pairs(p), 'ptext') for p in newparts] + [ValueTerminal('"', 'ptext')]) + if part.token_type == 'comment': + newparts = ( + [ValueTerminal('(', 'ptext')] + + [ValueTerminal(make_parenthesis_pairs(p), 'ptext') + if p.token_type == 'ptext' else p + for p in newparts] + + [ValueTerminal(')', 'ptext')]) if not part.as_ew_allowed: wrap_as_ew_blocked += 1 newparts.append(end_ew_not_allowed) Index: Python-3.12.12/Lib/test/test_email/test__header_value_parser.py =================================================================== --- Python-3.12.12.orig/Lib/test/test_email/test__header_value_parser.py 2026-02-06 00:08:37.343959625 +0100 +++ Python-3.12.12/Lib/test/test_email/test__header_value_parser.py 2026-02-06 00:08:40.747102748 +0100 @@ -3141,6 +3141,29 @@ with self.subTest(to=to): self._test(parser.get_address_list(to)[0], folded, policy=policy) + def test_address_list_with_long_unwrapable_comment(self): + policy = self.policy.clone(max_line_length=40) + cases = [ + # (to, folded) + ('(loremipsumdolorsitametconsecteturadipi)<[email protected]>', + '(loremipsumdolorsitametconsecteturadipi)<[email protected]>\n'), + ('<[email protected]>(loremipsumdolorsitametconsecteturadipi)', + '<[email protected]>(loremipsumdolorsitametconsecteturadipi)\n'), + ('(loremipsum dolorsitametconsecteturadipi)<[email protected]>', + '(loremipsum dolorsitametconsecteturadipi)<[email protected]>\n'), + ('<[email protected]>(loremipsum dolorsitametconsecteturadipi)', + '<[email protected]>(loremipsum\n dolorsitametconsecteturadipi)\n'), + ('(Escaped \\( \\) chars \\\\ in comments stay escaped)<[email protected]>', + '(Escaped \\( \\) chars \\\\ in comments stay\n escaped)<[email protected]>\n'), + ('((loremipsum)(loremipsum)(loremipsum)(loremipsum))<[email protected]>', + '((loremipsum)(loremipsum)(loremipsum)(loremipsum))<[email protected]>\n'), + ('((loremipsum)(loremipsum)(loremipsum) (loremipsum))<[email protected]>', + '((loremipsum)(loremipsum)(loremipsum)\n (loremipsum))<[email protected]>\n'), + ] + for (to, folded) in cases: + with self.subTest(to=to): + self._test(parser.get_address_list(to)[0], folded, policy=policy) + # 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. Index: Python-3.12.12/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ Python-3.12.12/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst 2026-02-06 00:08:40.747576711 +0100 @@ -0,0 +1,6 @@ +Fixed a bug in the folding of comments when flattening an email message +using a modern email policy. Comments consisting of a very long sequence of +non-foldable characters could trigger a forced line wrap that omitted the +required leading space on the continuation line, causing the remainder of +the comment to be interpreted as a new header field. This enabled header +injection with carefully crafted inputs. ++++++ CVE-2025-12781-b64decode-alt-chars.patch ++++++ >From f922c02c529d25d61aa9c28a8192639c1fce8d4d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka <[email protected]> Date: Wed, 5 Nov 2025 20:12:31 +0200 Subject: [PATCH] gh-125346: Add more base64 tests Add more tests for the altchars argument of b64decode() and for the map01 argument of b32decode(). --- Doc/library/base64.rst | 18 +++- Lib/base64.py | 40 ++++++++- Lib/test/test_base64.py | 42 +++++++++- Misc/NEWS.d/next/Library/2025-11-06-12-03-29.gh-issue-125346.7Gfpgw.rst | 5 + 4 files changed, 91 insertions(+), 14 deletions(-) Index: Python-3.12.12/Doc/library/base64.rst =================================================================== --- Python-3.12.12.orig/Doc/library/base64.rst 2025-10-09 13:07:00.000000000 +0200 +++ Python-3.12.12/Doc/library/base64.rst 2026-02-10 22:15:41.801235355 +0100 @@ -74,15 +74,20 @@ A :exc:`binascii.Error` exception is raised if *s* is incorrectly padded. - If *validate* is ``False`` (the default), characters that are neither + If *validate* is false (the default), characters that are neither in the normal base-64 alphabet nor the alternative alphabet are - discarded prior to the padding check. If *validate* is ``True``, - these non-alphabet characters in the input result in a - :exc:`binascii.Error`. + discarded prior to the padding check, but the ``+`` and ``/`` characters + keep their meaning if they are not in *altchars* (they will be discarded + in future Python versions). + If *validate* is true, these non-alphabet characters in the input + result in a :exc:`binascii.Error`. For more information about the strict base64 check, see :func:`binascii.a2b_base64` - May assert or raise a :exc:`ValueError` if the length of *altchars* is not 2. + .. deprecated:: next + Accepting the ``+`` and ``/`` characters with an alternative alphabet + is now deprecated. + .. function:: standard_b64encode(s) @@ -113,6 +118,9 @@ ``/`` in the standard Base64 alphabet, and return the decoded :class:`bytes`. + .. deprecated:: next + Accepting the ``+`` and ``/`` characters is now deprecated. + .. function:: b32encode(s) Index: Python-3.12.12/Lib/base64.py =================================================================== --- Python-3.12.12.orig/Lib/base64.py 2026-02-10 22:15:02.534016402 +0100 +++ Python-3.12.12/Lib/base64.py 2026-02-10 22:15:41.801591556 +0100 @@ -71,20 +71,39 @@ The result is returned as a bytes object. A binascii.Error is raised if s is incorrectly padded. - If validate is False (the default), characters that are neither in the + If validate is false (the default), characters that are neither in the normal base-64 alphabet nor the alternative alphabet are discarded prior - to the padding check. If validate is True, these non-alphabet characters + to the padding check. If validate is true, these non-alphabet characters in the input result in a binascii.Error. For more information about the strict base64 check, see: https://docs.python.org/3.11/library/binascii.html#binascii.a2b_base64 """ s = _bytes_from_decode_data(s) + badchar = None if altchars is not None: altchars = _bytes_from_decode_data(altchars) - assert len(altchars) == 2, repr(altchars) + if len(altchars) != 2: + raise ValueError(f'invalid altchars: {altchars!r}') + for b in b'+/': + if b not in altchars and b in s: + badchar = b + break s = s.translate(bytes.maketrans(altchars, b'+/')) - return binascii.a2b_base64(s, strict_mode=validate) + result = binascii.a2b_base64(s, strict_mode=validate) + if badchar is not None: + import warnings + if validate: + warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data ' + f'with altchars={altchars!r} and validate=True ' + f'will be an error in future Python versions', + DeprecationWarning, stacklevel=2) + else: + warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data ' + f'with altchars={altchars!r} and validate=False ' + f'will be discarded in future Python versions', + FutureWarning, stacklevel=2) + return result def standard_b64encode(s): @@ -129,8 +148,19 @@ The alphabet uses '-' instead of '+' and '_' instead of '/'. """ s = _bytes_from_decode_data(s) + badchar = None + for b in b'+/': + if b in s: + badchar = b + break s = s.translate(_urlsafe_decode_translation) - return b64decode(s) + result = binascii.a2b_base64(s, strict_mode=False) + if badchar is not None: + import warnings + warnings.warn(f'invalid character {chr(badchar)!a} in URL-safe Base64 data ' + f'will be discarded in future Python versions', + FutureWarning, stacklevel=2) + return result Index: Python-3.12.12/Lib/test/test_base64.py =================================================================== --- Python-3.12.12.orig/Lib/test/test_base64.py 2026-02-10 22:15:04.364274059 +0100 +++ Python-3.12.12/Lib/test/test_base64.py 2026-02-10 22:17:42.445725550 +0100 @@ -232,6 +232,25 @@ b'\xd3V\xbeo\xf7\x1d') self.check_decode_type_errors(base64.urlsafe_b64decode) + def test_b64decode_altchars(self): + # Test with arbitrary alternative characters + eq = self.assertEqual + res = b'\xd3V\xbeo\xf7\x1d' + for altchars in b'*$', b'+/', b'/+', b'+_', b'-+', b'-/', b'/_': + data = b'01a%cb%ccd' % tuple(altchars) + data_str = data.decode('ascii') + altchars_str = altchars.decode('ascii') + + eq(base64.b64decode(data, altchars=altchars), res) + eq(base64.b64decode(data_str, altchars=altchars), res) + eq(base64.b64decode(data, altchars=altchars_str), res) + eq(base64.b64decode(data_str, altchars=altchars_str), res) + + self.assertRaises(ValueError, base64.b64decode, b'', altchars=b'+') + self.assertRaises(ValueError, base64.b64decode, b'', altchars=b'+/-') + self.assertRaises(ValueError, base64.b64decode, '', altchars='+') + self.assertRaises(ValueError, base64.b64decode, '', altchars='+/-') + def test_b64decode_padding_error(self): self.assertRaises(binascii.Error, base64.b64decode, b'abc') self.assertRaises(binascii.Error, base64.b64decode, 'abc') @@ -263,10 +282,25 @@ with self.assertRaises(binascii.Error): base64.b64decode(bstr.decode('ascii'), validate=True) - # Normal alphabet characters not discarded when alternative given - res = b'\xFB\xEF\xBE\xFF\xFF\xFF' - self.assertEqual(base64.b64decode(b'++[[//]]', b'[]'), res) - self.assertEqual(base64.urlsafe_b64decode(b'++--//__'), res) + # Normal alphabet characters will be discarded when alternative given + with self.assertWarns(FutureWarning): + self.assertEqual(base64.b64decode(b'++++', altchars=b'-_'), + b'\xfb\xef\xbe') + with self.assertWarns(FutureWarning): + self.assertEqual(base64.b64decode(b'////', altchars=b'-_'), + b'\xff\xff\xff') + with self.assertWarns(DeprecationWarning): + self.assertEqual(base64.b64decode(b'++++', altchars=b'-_', validate=True), + b'\xfb\xef\xbe') + with self.assertWarns(DeprecationWarning): + self.assertEqual(base64.b64decode(b'////', altchars=b'-_', validate=True), + b'\xff\xff\xff') + with self.assertWarns(FutureWarning): + self.assertEqual(base64.urlsafe_b64decode(b'++++'), b'\xfb\xef\xbe') + with self.assertWarns(FutureWarning): + self.assertEqual(base64.urlsafe_b64decode(b'////'), b'\xff\xff\xff') + with self.assertRaises(binascii.Error): + base64.b64decode(b'+/!', altchars=b'-_') def test_b32encode(self): eq = self.assertEqual Index: Python-3.12.12/Misc/NEWS.d/next/Library/2025-11-06-12-03-29.gh-issue-125346.7Gfpgw.rst =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ Python-3.12.12/Misc/NEWS.d/next/Library/2025-11-06-12-03-29.gh-issue-125346.7Gfpgw.rst 2026-02-10 22:15:41.802353823 +0100 @@ -0,0 +1,5 @@ +Accepting ``+`` and ``/`` characters with an alternative alphabet in +:func:`base64.b64decode` and :func:`base64.urlsafe_b64decode` is now +deprecated. +In future Python versions they will be errors in the strict mode and +discarded in the non-strict mode. ++++++ CVE-2025-15282-urllib-ctrl-chars.patch ++++++ >From f336af1c4b103297de1322bbe00f920f3e58b899 Mon Sep 17 00:00:00 2001 From: Seth Michael Larson <[email protected]> Date: Tue, 20 Jan 2026 14:45:58 -0600 Subject: [PATCH 1/2] [3.12] gh-143925: Reject control characters in data: URL mediatypes (cherry picked from commit f25509e78e8be6ea73c811ac2b8c928c28841b9f) (cherry picked from commit 2c9c746077d8119b5bcf5142316992e464594946) Co-authored-by: Seth Michael Larson <[email protected]> --- Lib/test/test_urllib.py | 8 ++++++++ Lib/urllib/request.py | 5 +++++ Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst | 1 + 3 files changed, 14 insertions(+) create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst Index: Python-3.12.12/Lib/test/test_urllib.py =================================================================== --- Python-3.12.12.orig/Lib/test/test_urllib.py 2026-02-10 22:15:06.355594386 +0100 +++ Python-3.12.12/Lib/test/test_urllib.py 2026-02-10 22:18:23.820760279 +0100 @@ -12,6 +12,7 @@ from test.support import os_helper from test.support import socket_helper from test.support import warnings_helper +from test.support import control_characters_c0 import os try: import ssl @@ -688,6 +689,13 @@ # missing padding character self.assertRaises(ValueError,urllib.request.urlopen,'data:;base64,Cg=') + def test_invalid_mediatype(self): + for c0 in control_characters_c0(): + self.assertRaises(ValueError,urllib.request.urlopen, + f'data:text/html;{c0},data') + for c0 in control_characters_c0(): + self.assertRaises(ValueError,urllib.request.urlopen, + f'data:text/html{c0};base64,ZGF0YQ==') class urlretrieve_FileTests(unittest.TestCase): """Test urllib.urlretrieve() on local files""" Index: Python-3.12.12/Lib/urllib/request.py =================================================================== --- Python-3.12.12.orig/Lib/urllib/request.py 2026-02-10 22:15:06.739534061 +0100 +++ Python-3.12.12/Lib/urllib/request.py 2026-02-10 22:18:23.819325524 +0100 @@ -1655,6 +1655,11 @@ scheme, data = url.split(":",1) mediatype, data = data.split(",",1) + # Disallow control characters within mediatype. + if re.search(r"[\x00-\x1F\x7F]", mediatype): + raise ValueError( + "Control characters not allowed in data: mediatype") + # even base64 encoded data URLs might be quoted so unquote in any case: data = unquote_to_bytes(data) if mediatype.endswith(";base64"): Index: Python-3.12.12/Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ Python-3.12.12/Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst 2026-02-10 22:18:23.819830797 +0100 @@ -0,0 +1 @@ +Reject control characters in ``data:`` URL media types. ++++++ CVE-2025-15366-imap-ctrl-chars.patch ++++++ >From 7485ee5e2cf81d3e5ad0d9c3be73cecd2ab4eec7 Mon Sep 17 00:00:00 2001 From: Seth Michael Larson <[email protected]> Date: Fri, 16 Jan 2026 10:54:09 -0600 Subject: [PATCH 1/2] Add 'test.support' fixture for C0 control characters --- Lib/imaplib.py | 4 +++- Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) Index: Python-3.12.12/Lib/imaplib.py =================================================================== --- Python-3.12.12.orig/Lib/imaplib.py 2026-02-10 22:15:03.417592955 +0100 +++ Python-3.12.12/Lib/imaplib.py 2026-02-10 22:18:02.094605035 +0100 @@ -132,7 +132,7 @@ # We compile these in _mode_xxx. _Literal = br'.*{(?P<size>\d+)}$' _Untagged_status = br'\* (?P<data>\d+) (?P<type>[A-Z-]+)( (?P<data2>.*))?' - +_control_chars = re.compile(b'[\x00-\x1F\x7F]') class IMAP4: @@ -994,6 +994,8 @@ if arg is None: continue if isinstance(arg, str): arg = bytes(arg, self._encoding) + if _control_chars.search(arg): + raise ValueError("Control characters not allowed in commands") data = data + b' ' + arg literal = self.literal Index: Python-3.12.12/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ Python-3.12.12/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst 2026-02-10 22:18:02.095167966 +0100 @@ -0,0 +1 @@ +Reject control characters in IMAP commands. ++++++ CVE-2025-15367-poplib-ctrl-chars.patch ++++++ >From b6f733b285b1c4f27dacb5c2e1f292c914e8b933 Mon Sep 17 00:00:00 2001 From: Seth Michael Larson <[email protected]> Date: Fri, 16 Jan 2026 10:54:09 -0600 Subject: [PATCH 1/2] Add 'test.support' fixture for C0 control characters --- Lib/poplib.py | 2 ++ Lib/test/test_poplib.py | 8 ++++++++ Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst | 1 + 3 files changed, 11 insertions(+) Index: Python-3.12.12/Lib/poplib.py =================================================================== --- Python-3.12.12.orig/Lib/poplib.py 2026-02-11 23:46:29.442215955 +0100 +++ Python-3.12.12/Lib/poplib.py 2026-02-11 23:46:46.713251058 +0100 @@ -122,6 +122,8 @@ def _putcmd(self, line): if self._debugging: print('*cmd*', repr(line)) line = bytes(line, self.encoding) + if re.search(b'[\x00-\x1F\x7F]', line): + raise ValueError('Control characters not allowed in commands') self._putline(line) Index: Python-3.12.12/Lib/test/test_poplib.py =================================================================== --- Python-3.12.12.orig/Lib/test/test_poplib.py 2026-02-11 23:46:31.636412813 +0100 +++ Python-3.12.12/Lib/test/test_poplib.py 2026-02-11 23:46:46.713442229 +0100 @@ -17,6 +17,7 @@ from test.support import threading_helper from test.support import asynchat from test.support import asyncore +from test.support import control_characters_c0 test_support.requires_working_socket(module=True) @@ -395,6 +396,13 @@ self.assertIsNone(self.client.sock) self.assertIsNone(self.client.file) + def test_control_characters(self): + for c0 in control_characters_c0(): + with self.assertRaises(ValueError): + self.client.user(f'user{c0}') + with self.assertRaises(ValueError): + self.client.pass_(f'{c0}pass') + @requires_ssl def test_stls_capa(self): capa = self.client.capa() Index: Python-3.12.12/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ Python-3.12.12/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst 2026-02-11 23:46:46.713620996 +0100 @@ -0,0 +1 @@ +Reject control characters in POP3 commands. ++++++ CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch ++++++ >From 9729bdf210967c806f3364c76663fc2ade58e389 Mon Sep 17 00:00:00 2001 From: Seth Michael Larson <[email protected]> Date: Tue, 20 Jan 2026 15:23:42 -0600 Subject: [PATCH] gh-143919: Reject control characters in http cookies (cherry picked from commit 95746b3a13a985787ef53b977129041971ed7f70) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Seth Michael Larson <[email protected]> Co-authored-by: Bartosz Sławecki <[email protected]> Co-authored-by: sobolevn <[email protected]> --- Doc/library/http.cookies.rst | 4 Lib/http/cookies.py | 25 ++++ Lib/test/test_http_cookies.py | 52 +++++++++- Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst | 1 4 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst Index: Python-3.12.12/Doc/library/http.cookies.rst =================================================================== --- Python-3.12.12.orig/Doc/library/http.cookies.rst 2025-10-09 13:07:00.000000000 +0200 +++ Python-3.12.12/Doc/library/http.cookies.rst 2026-02-10 22:17:53.970413039 +0100 @@ -272,9 +272,9 @@ Set-Cookie: chips=ahoy Set-Cookie: vienna=finger >>> C = cookies.SimpleCookie() - >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";') + >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=;";') >>> print(C) - Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;" + Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=;" >>> C = cookies.SimpleCookie() >>> C["oreo"] = "doublestuff" >>> C["oreo"]["path"] = "/" Index: Python-3.12.12/Lib/http/cookies.py =================================================================== --- Python-3.12.12.orig/Lib/http/cookies.py 2026-02-10 22:15:03.102916960 +0100 +++ Python-3.12.12/Lib/http/cookies.py 2026-02-10 22:17:53.970584713 +0100 @@ -87,9 +87,9 @@ such trickeries do not confuse it. >>> C = cookies.SimpleCookie() - >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";') + >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=;";') >>> print(C) - Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;" + Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=;" Each element of the Cookie also supports all of the RFC 2109 Cookie attributes. Here's an example which sets the Path @@ -170,6 +170,15 @@ }) _is_legal_key = re.compile('[%s]+' % re.escape(_LegalChars)).fullmatch +_control_character_re = re.compile(r'[\x00-\x1F\x7F]') + + +def _has_control_character(*val): + """Detects control characters within a value. + Supports any type, as header values can be any type. + """ + return any(_control_character_re.search(str(v)) for v in val) + def _quote(str): r"""Quote a string for use in a cookie header. @@ -292,12 +301,16 @@ K = K.lower() if not K in self._reserved: raise CookieError("Invalid attribute %r" % (K,)) + if _has_control_character(K, V): + raise CookieError(f"Control characters are not allowed in cookies {K!r} {V!r}") dict.__setitem__(self, K, V) def setdefault(self, key, val=None): key = key.lower() if key not in self._reserved: raise CookieError("Invalid attribute %r" % (key,)) + if _has_control_character(key, val): + raise CookieError("Control characters are not allowed in cookies %r %r" % (key, val,)) return dict.setdefault(self, key, val) def __eq__(self, morsel): @@ -333,6 +346,9 @@ raise CookieError('Attempt to set a reserved key %r' % (key,)) if not _is_legal_key(key): raise CookieError('Illegal key %r' % (key,)) + if _has_control_character(key, val, coded_val): + raise CookieError( + "Control characters are not allowed in cookies %r %r %r" % (key, val, coded_val,)) # It's a good key, so save it. self._key = key @@ -486,7 +502,10 @@ result = [] items = sorted(self.items()) for key, value in items: - result.append(value.output(attrs, header)) + value_output = value.output(attrs, header) + if _has_control_character(value_output): + raise CookieError("Control characters are not allowed in cookies") + result.append(value_output) return sep.join(result) __str__ = output Index: Python-3.12.12/Lib/test/test_http_cookies.py =================================================================== --- Python-3.12.12.orig/Lib/test/test_http_cookies.py 2026-02-10 22:15:05.120676729 +0100 +++ Python-3.12.12/Lib/test/test_http_cookies.py 2026-02-10 22:17:53.970780833 +0100 @@ -17,10 +17,10 @@ 'repr': "<SimpleCookie: chips='ahoy' vienna='finger'>", 'output': 'Set-Cookie: chips=ahoy\nSet-Cookie: vienna=finger'}, - {'data': 'keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"', - 'dict': {'keebler' : 'E=mc2; L="Loves"; fudge=\012;'}, - 'repr': '''<SimpleCookie: keebler='E=mc2; L="Loves"; fudge=\\n;'>''', - 'output': 'Set-Cookie: keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"'}, + {'data': 'keebler="E=mc2; L=\\"Loves\\"; fudge=;"', + 'dict': {'keebler' : 'E=mc2; L="Loves"; fudge=;'}, + 'repr': '''<SimpleCookie: keebler='E=mc2; L="Loves"; fudge=;'>''', + 'output': 'Set-Cookie: keebler="E=mc2; L=\\"Loves\\"; fudge=;"'}, # Check illegal cookies that have an '=' char in an unquoted value {'data': 'keebler=E=mc2', @@ -563,6 +563,50 @@ r'Set-Cookie: key=coded_val; ' r'expires=\w+, \d+ \w+ \d+ \d+:\d+:\d+ \w+') + def test_control_characters(self): + for c0 in support.control_characters_c0(): + morsel = cookies.Morsel() + + # .__setitem__() + with self.assertRaises(cookies.CookieError): + morsel[c0] = "val" + with self.assertRaises(cookies.CookieError): + morsel["path"] = c0 + + # .setdefault() + with self.assertRaises(cookies.CookieError): + morsel.setdefault("path", c0) + with self.assertRaises(cookies.CookieError): + morsel.setdefault(c0, "val") + + # .set() + with self.assertRaises(cookies.CookieError): + morsel.set(c0, "val", "coded-value") + with self.assertRaises(cookies.CookieError): + morsel.set("path", c0, "coded-value") + with self.assertRaises(cookies.CookieError): + morsel.set("path", "val", c0) + + def test_control_characters_output(self): + # Tests that even if the internals of Morsel are modified + # that a call to .output() has control character safeguards. + for c0 in support.control_characters_c0(): + morsel = cookies.Morsel() + morsel.set("key", "value", "coded-value") + morsel._key = c0 # Override private variable. + cookie = cookies.SimpleCookie() + cookie["cookie"] = morsel + with self.assertRaises(cookies.CookieError): + cookie.output() + + morsel = cookies.Morsel() + morsel.set("key", "value", "coded-value") + morsel._coded_value = c0 # Override private variable. + cookie = cookies.SimpleCookie() + cookie["cookie"] = morsel + with self.assertRaises(cookies.CookieError): + cookie.output() + def load_tests(loader, tests, pattern): tests.addTest(doctest.DocTestSuite(cookies)) Index: Python-3.12.12/Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ Python-3.12.12/Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst 2026-02-10 22:17:53.970970320 +0100 @@ -0,0 +1 @@ +Reject control characters in :class:`http.cookies.Morsel` fields and values. ++++++ CVE-2026-0865-wsgiref-ctrl-chars.patch ++++++ >From 03a7342c9e2bbdab20a6d882bf334608dc7a5d4b Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" <[email protected]> Date: Sat, 17 Jan 2026 10:23:57 -0800 Subject: [PATCH] [3.12] gh-143916: Reject control characters in wsgiref.headers.Headers (GH-143917) (GH-143973) gh-143916: Reject control characters in wsgiref.headers.Headers (GH-143917) * Add 'test.support' fixture for C0 control characters * gh-143916: Reject control characters in wsgiref.headers.Headers (cherry picked from commit f7fceed79ca1bceae8dbe5ba5bc8928564da7211) (cherry picked from commit 22e4d55285cee52bc4dbe061324e5f30bd4dee58) Co-authored-by: Gregory P. Smith <[email protected]> Co-authored-by: Seth Michael Larson <[email protected]> --- Lib/test/support/__init__.py | 7 +++++ Lib/test/test_wsgiref.py | 12 +++++++++- Lib/wsgiref/headers.py | 3 ++ Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst | 2 + 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst Index: Python-3.12.12/Lib/test/support/__init__.py =================================================================== --- Python-3.12.12.orig/Lib/test/support/__init__.py 2026-02-10 22:15:04.163026806 +0100 +++ Python-3.12.12/Lib/test/support/__init__.py 2026-02-10 22:17:57.451276662 +0100 @@ -2591,3 +2591,10 @@ if self.iter_raises: 1/0 return self + + +def control_characters_c0() -> list[str]: + """Returns a list of C0 control characters as strings. + C0 control characters defined as the byte range 0x00-0x1F, and 0x7F. + """ + return [chr(c) for c in range(0x00, 0x20)] + ["\x7F"] Index: Python-3.12.12/Lib/test/test_wsgiref.py =================================================================== --- Python-3.12.12.orig/Lib/test/test_wsgiref.py 2026-02-10 22:15:06.432657502 +0100 +++ Python-3.12.12/Lib/test/test_wsgiref.py 2026-02-10 22:17:57.451566378 +0100 @@ -1,6 +1,6 @@ from unittest import mock from test import support -from test.support import socket_helper +from test.support import socket_helper, control_characters_c0 from test.test_httpservers import NoLogRequestHandler from unittest import TestCase from wsgiref.util import setup_testing_defaults @@ -503,6 +503,16 @@ '\r\n' ) + def testRaisesControlCharacters(self): + headers = Headers() + for c0 in control_characters_c0(): + self.assertRaises(ValueError, headers.__setitem__, f"key{c0}", "val") + self.assertRaises(ValueError, headers.__setitem__, "key", f"val{c0}") + self.assertRaises(ValueError, headers.add_header, f"key{c0}", "val", param="param") + self.assertRaises(ValueError, headers.add_header, "key", f"val{c0}", param="param") + self.assertRaises(ValueError, headers.add_header, "key", "val", param=f"param{c0}") + + class ErrorHandler(BaseCGIHandler): """Simple handler subclass for testing BaseHandler""" Index: Python-3.12.12/Lib/wsgiref/headers.py =================================================================== --- Python-3.12.12.orig/Lib/wsgiref/headers.py 2026-02-10 22:15:06.773169140 +0100 +++ Python-3.12.12/Lib/wsgiref/headers.py 2026-02-10 22:17:57.451729575 +0100 @@ -9,6 +9,7 @@ # existence of which force quoting of the parameter value. import re tspecials = re.compile(r'[ \(\)<>@,;:\\"/\[\]\?=]') +_control_chars_re = re.compile(r'[\x00-\x1F\x7F]') def _formatparam(param, value=None, quote=1): """Convenience function to format and return a key=value pair. @@ -41,6 +42,8 @@ def _convert_string_type(self, value): """Convert/check value type.""" if type(value) is str: + if _control_chars_re.search(value): + raise ValueError("Control characters not allowed in headers") return value raise AssertionError("Header names/values must be" " of type str (got {0})".format(repr(value))) Index: Python-3.12.12/Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ Python-3.12.12/Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst 2026-02-10 22:17:57.451848490 +0100 @@ -0,0 +1,2 @@ +Reject C0 control characters within wsgiref.headers.Headers fields, values, +and parameters. ++++++ _scmsync.obsinfo ++++++ --- /var/tmp/diff_new_pack.vwuuUW/_old 2026-02-18 17:05:21.881561081 +0100 +++ /var/tmp/diff_new_pack.vwuuUW/_new 2026-02-18 17:05:21.889561413 +0100 @@ -1,6 +1,6 @@ -mtime: 1766171591 -commit: 3ec5b189c8398b00c1828ce95bd81824ae2a9b8e0ba6d3653dd2b58d3b35352d +mtime: 1770850038 +commit: 07beab470daf1bea6b0fbc6af7e3bd5f0a9f708806d74c128490c9fb47a3bd6d url: https://src.opensuse.org/python-interpreters/python312.git -revision: 3ec5b189c8398b00c1828ce95bd81824ae2a9b8e0ba6d3653dd2b58d3b35352d +revision: 07beab470daf1bea6b0fbc6af7e3bd5f0a9f708806d74c128490c9fb47a3bd6d projectscmsync: https://src.opensuse.org/python-interpreters/_ObsPrj ++++++ build.specials.obscpio ++++++ ++++++ build.specials.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.gitignore new/.gitignore --- old/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/.gitignore 2026-02-11 23:47:34.000000000 +0100 @@ -0,0 +1,5 @@ +.osc +*.obscpio +_build.* +.pbuild +python312-3.12.*-build
