Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python315 for openSUSE:Factory checked in at 2026-02-05 18:01:15 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python315 (Old) and /work/SRC/openSUSE:Factory/.python315.new.1670 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python315" Thu Feb 5 18:01:15 2026 rev:6 rq:1331423 version:3.15.0~a3 Changes: -------- --- /work/SRC/openSUSE:Factory/python315/python315.changes 2026-01-30 18:22:31.006108200 +0100 +++ /work/SRC/openSUSE:Factory/.python315.new.1670/python315.changes 2026-02-05 18:06:55.012010080 +0100 @@ -1,0 +2,21 @@ +Wed Feb 4 00:53:37 UTC 2026 - Matej Cepl <[email protected]> + +- Add CVE-2025-12781-b64decode-alt-chars.patch fixing bsc#1257108 + (CVE-2025-12781) combining gh#python/cpython!141061, + gh#python/cpython!141128, and gh#python/cpython!141153. All + `*b64decode` functions should not accept non-altchars. +- Add CVE-2026-0865-wsgiref-ctrl-chars.patch fixing bsc#1257042 + (CVE-2026-0865) rejecting control characters in + wsgiref.headers.Headers, which could be abused for injecting + false HTTP headers. +- Add CVE-2025-15366-imap-ctrl-chars.patch fixing bsc#1257044 + (CVE-2025-15366) using gh#python/cpython!143922 and doing + basically the same as the previous patch for IMAP protocol. +- Add CVE-2025-15282-urllib-ctrl-chars.patch fixing bsc#1257046 + (CVE-2025-15282) using gh#python/cpython!143926 and doing + basically the same as the previous patch for urllib library. +- Add CVE-2025-15367-poplib-ctrl-chars.patch fixing bsc#1257041 + (CVE-2025-15367) using gh#python/cpython!143924 and doing + basically the same as the previous patch for poplib library. + +------------------------------------------------------------------- New: ---- 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-0865-wsgiref-ctrl-chars.patch ----------(New B)---------- New: - Add CVE-2025-12781-b64decode-alt-chars.patch fixing bsc#1257108 (CVE-2025-12781) combining gh#python/cpython!141061, New: basically the same as the previous patch for IMAP protocol. - Add CVE-2025-15282-urllib-ctrl-chars.patch fixing bsc#1257046 (CVE-2025-15282) using gh#python/cpython!143926 and doing New: false HTTP headers. - Add CVE-2025-15366-imap-ctrl-chars.patch fixing bsc#1257044 (CVE-2025-15366) using gh#python/cpython!143922 and doing New: basically the same as the previous patch for urllib library. - Add CVE-2025-15367-poplib-ctrl-chars.patch fixing bsc#1257041 (CVE-2025-15367) using gh#python/cpython!143924 and doing New: `*b64decode` functions should not accept non-altchars. - Add CVE-2026-0865-wsgiref-ctrl-chars.patch fixing bsc#1257042 (CVE-2026-0865) rejecting control characters in ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python315.spec ++++++ --- /var/tmp/diff_new_pack.PI41Gf/_old 2026-02-05 18:06:56.312064695 +0100 +++ /var/tmp/diff_new_pack.PI41Gf/_new 2026-02-05 18:06:56.316064864 +0100 @@ -238,6 +238,21 @@ # PATCH-FIX-UPSTREAM CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch bsc#1257031 [email protected] # Reject control characters in http cookies Patch46: CVE-2026-0672-http-hdr-inject-cookie-Morsel.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 +Patch47: CVE-2025-12781-b64decode-alt-chars.patch +# PATCH-FIX-UPSTREAM CVE-2026-0865-wsgiref-ctrl-chars.patch bsc#1257042 [email protected] +# Reject control characters in wsgiref.headers.Headers +Patch48: 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 +Patch49: 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 wsgiref.headers.Headers +Patch50: 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 +Patch51: CVE-2025-15367-poplib-ctrl-chars.patch #### Python 3.15 DEVELOPMENT PATCHES BuildRequires: autoconf-archive BuildRequires: automake ++++++ 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 ++-- Doc/whatsnew/3.15.rst | 9 ++ Lib/base64.py | 40 +++++++- Lib/test/test_base64.py | 45 ++++++++-- Misc/NEWS.d/next/Library/2025-11-06-12-03-29.gh-issue-125346.7Gfpgw.rst | 5 + 5 files changed, 100 insertions(+), 17 deletions(-) Index: Python-3.15.0a3/Doc/library/base64.rst =================================================================== --- Python-3.15.0a3.orig/Doc/library/base64.rst 2025-12-16 13:26:12.000000000 +0100 +++ Python-3.15.0a3/Doc/library/base64.rst 2026-02-03 16:15:09.480009542 +0100 @@ -77,15 +77,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) @@ -116,6 +121,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.15.0a3/Doc/whatsnew/3.15.rst =================================================================== --- Python-3.15.0a3.orig/Doc/whatsnew/3.15.rst 2025-12-16 13:26:12.000000000 +0100 +++ Python-3.15.0a3/Doc/whatsnew/3.15.rst 2026-02-03 16:15:09.480398395 +0100 @@ -992,6 +992,15 @@ New deprecations ---------------- +* :mod:`base64`: + + * Accepting the ``+`` 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. + (Contributed by Serhiy Storchaka in :gh:`125346`.) + * CLI: * Deprecate :option:`-b` and :option:`!-bb` command-line options Index: Python-3.15.0a3/Lib/base64.py =================================================================== --- Python-3.15.0a3.orig/Lib/base64.py 2026-02-03 16:13:28.034477672 +0100 +++ Python-3.15.0a3/Lib/base64.py 2026-02-03 16:15:09.480836931 +0100 @@ -69,20 +69,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): @@ -127,8 +146,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.15.0a3/Lib/test/test_base64.py =================================================================== --- Python-3.15.0a3.orig/Lib/test/test_base64.py 2026-02-03 16:13:29.357990779 +0100 +++ Python-3.15.0a3/Lib/test/test_base64.py 2026-02-03 16:15:09.481134341 +0100 @@ -265,6 +265,25 @@ eq(base64.b64decode(data, altchars=altchars_str), res) eq(base64.b64decode(data_str, altchars=altchars_str), res) + 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') @@ -296,13 +315,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\xff' - self.assertEqual(base64.b64decode(b'++//', validate=True), res) - self.assertEqual(base64.b64decode(b'++//', '-_', validate=True), res) - self.assertEqual(base64.b64decode(b'--__', '-_', validate=True), res) - self.assertEqual(base64.urlsafe_b64decode(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 _altchars_strategy(): """Generate 'altchars' for base64 encoding.""" Index: Python-3.15.0a3/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.15.0a3/Misc/NEWS.d/next/Library/2025-11-06-12-03-29.gh-issue-125346.7Gfpgw.rst 2026-02-03 16:15:09.481407075 +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 d8850aac54c234201966c66e83225564302cd15c 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/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(+) Index: Python-3.15.0a3/Lib/test/test_urllib.py =================================================================== --- Python-3.15.0a3.orig/Lib/test/test_urllib.py 2026-02-04 16:57:42.070871001 +0100 +++ Python-3.15.0a3/Lib/test/test_urllib.py 2026-02-04 16:57:49.106800440 +0100 @@ -10,6 +10,7 @@ from test import support from test.support import os_helper from test.support import socket_helper +from test.support import control_characters_c0 import os import socket try: @@ -590,6 +591,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.15.0a3/Lib/urllib/request.py =================================================================== --- Python-3.15.0a3.orig/Lib/urllib/request.py 2026-02-04 16:57:42.390604584 +0100 +++ Python-3.15.0a3/Lib/urllib/request.py 2026-02-04 16:57:49.107133794 +0100 @@ -1634,6 +1634,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.15.0a3/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.15.0a3/Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst 2026-02-04 16:57:49.107422870 +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 +++- Lib/test/test_imaplib.py | 6 ++++++ Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) Index: Python-3.15.0a3/Lib/imaplib.py =================================================================== --- Python-3.15.0a3.orig/Lib/imaplib.py 2026-02-04 10:33:17.226345322 +0100 +++ Python-3.15.0a3/Lib/imaplib.py 2026-02-04 10:33:45.757970971 +0100 @@ -129,7 +129,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: @@ -1105,6 +1105,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.15.0a3/Lib/test/test_imaplib.py =================================================================== --- Python-3.15.0a3.orig/Lib/test/test_imaplib.py 2026-02-04 10:33:18.559328359 +0100 +++ Python-3.15.0a3/Lib/test/test_imaplib.py 2026-02-04 10:33:45.758227151 +0100 @@ -657,6 +657,12 @@ self.assertEqual(data[0], b'Returned to authenticated state. (Success)') self.assertEqual(client.state, 'AUTH') + def test_control_characters(self): + client, _ = self._setup(SimpleIMAPHandler) + for c0 in support.control_characters_c0(): + with self.assertRaises(ValueError): + client.login(f'user{c0}', 'pass') + # property tests def test_file_property_should_not_be_accessed(self): Index: Python-3.15.0a3/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.15.0a3/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst 2026-02-04 10:33:45.758408531 +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.15.0a3/Lib/poplib.py =================================================================== --- Python-3.15.0a3.orig/Lib/poplib.py 2026-02-04 20:53:38.757990472 +0100 +++ Python-3.15.0a3/Lib/poplib.py 2026-02-04 20:53:46.764343586 +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.15.0a3/Lib/test/test_poplib.py =================================================================== --- Python-3.15.0a3.orig/Lib/test/test_poplib.py 2026-02-04 20:53:40.553673802 +0100 +++ Python-3.15.0a3/Lib/test/test_poplib.py 2026-02-04 20:53:46.764523568 +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.15.0a3/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.15.0a3/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst 2026-02-04 20:53:46.764674776 +0100 @@ -0,0 +1 @@ +Reject control characters in POP3 commands. ++++++ CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch ++++++ --- /var/tmp/diff_new_pack.PI41Gf/_old 2026-02-05 18:06:56.440070073 +0100 +++ /var/tmp/diff_new_pack.PI41Gf/_new 2026-02-05 18:06:56.452070577 +0100 @@ -14,7 +14,7 @@ Index: Python-3.15.0a3/Doc/library/http.cookies.rst =================================================================== --- Python-3.15.0a3.orig/Doc/library/http.cookies.rst 2025-12-16 13:26:12.000000000 +0100 -+++ Python-3.15.0a3/Doc/library/http.cookies.rst 2026-01-29 14:05:16.590570536 +0100 ++++ Python-3.15.0a3/Doc/library/http.cookies.rst 2026-02-03 16:13:34.510285255 +0100 @@ -294,9 +294,9 @@ Set-Cookie: chips=ahoy Set-Cookie: vienna=finger @@ -29,8 +29,8 @@ >>> C["oreo"]["path"] = "/" Index: Python-3.15.0a3/Lib/http/cookies.py =================================================================== ---- Python-3.15.0a3.orig/Lib/http/cookies.py 2026-01-29 14:04:58.842924007 +0100 -+++ Python-3.15.0a3/Lib/http/cookies.py 2026-01-29 14:05:16.590357855 +0100 +--- Python-3.15.0a3.orig/Lib/http/cookies.py 2026-02-03 16:13:28.474908366 +0100 ++++ Python-3.15.0a3/Lib/http/cookies.py 2026-02-03 16:13:34.510714274 +0100 @@ -87,9 +87,9 @@ such trickeries do not confuse it. @@ -100,8 +100,8 @@ __str__ = output Index: Python-3.15.0a3/Lib/test/support/__init__.py =================================================================== ---- Python-3.15.0a3.orig/Lib/test/support/__init__.py 2026-01-29 14:04:59.594499984 +0100 -+++ Python-3.15.0a3/Lib/test/support/__init__.py 2026-01-29 14:05:16.588221721 +0100 +--- Python-3.15.0a3.orig/Lib/test/support/__init__.py 2026-02-03 16:13:29.187789397 +0100 ++++ Python-3.15.0a3/Lib/test/support/__init__.py 2026-02-03 16:13:34.511147760 +0100 @@ -3272,3 +3272,10 @@ return _linked_to_musl _linked_to_musl = tuple(map(int, version.split('.'))) @@ -115,8 +115,8 @@ + return [chr(c) for c in range(0x00, 0x20)] + ["\x7F"] Index: Python-3.15.0a3/Lib/test/test_http_cookies.py =================================================================== ---- Python-3.15.0a3.orig/Lib/test/test_http_cookies.py 2026-01-29 14:05:00.455994675 +0100 -+++ Python-3.15.0a3/Lib/test/test_http_cookies.py 2026-01-29 14:05:16.590146527 +0100 +--- Python-3.15.0a3.orig/Lib/test/test_http_cookies.py 2026-02-03 16:13:29.999878162 +0100 ++++ Python-3.15.0a3/Lib/test/test_http_cookies.py 2026-02-03 16:13:34.511648955 +0100 @@ -17,10 +17,10 @@ 'repr': "<SimpleCookie: chips='ahoy' vienna='finger'>", 'output': 'Set-Cookie: chips=ahoy\nSet-Cookie: vienna=finger'}, @@ -186,7 +186,7 @@ Index: Python-3.15.0a3/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.15.0a3/Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst 2026-01-29 14:05:16.589009315 +0100 ++++ Python-3.15.0a3/Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst 2026-02-03 16:13:34.512041144 +0100 @@ -0,0 +1 @@ +Reject control characters in :class:`http.cookies.Morsel` fields and values. ++++++ CVE-2026-0865-wsgiref-ctrl-chars.patch ++++++ >From e7f180b4c21576f52c08933a184d84dc4b47e00e 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/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 + 3 files changed, 16 insertions(+), 1 deletion(-) Index: Python-3.15.0a3/Lib/test/test_wsgiref.py =================================================================== --- Python-3.15.0a3.orig/Lib/test/test_wsgiref.py 2026-02-04 01:52:45.393433768 +0100 +++ Python-3.15.0a3/Lib/test/test_wsgiref.py 2026-02-04 01:52:52.928458181 +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.15.0a3/Lib/wsgiref/headers.py =================================================================== --- Python-3.15.0a3.orig/Lib/wsgiref/headers.py 2026-02-04 01:52:45.666384529 +0100 +++ Python-3.15.0a3/Lib/wsgiref/headers.py 2026-02-04 01:52:52.928606420 +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.15.0a3/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.15.0a3/Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst 2026-02-04 01:52:52.928707130 +0100 @@ -0,0 +1,2 @@ +Reject C0 control characters within wsgiref.headers.Headers fields, values, +and parameters. ++++++ _scmsync.obsinfo ++++++ --- /var/tmp/diff_new_pack.PI41Gf/_old 2026-02-05 18:06:57.024094608 +0100 +++ /var/tmp/diff_new_pack.PI41Gf/_new 2026-02-05 18:06:57.076096792 +0100 @@ -1,6 +1,6 @@ -mtime: 1769691931 -commit: 699574482616cd14535b890206a88920be7ee5f0f66abeece2826d05df83d092 +mtime: 1770240166 +commit: 3312e86ee4a2708afdaa23ebdcf981dbd3c3306d7f68bb406a9e3f321c0a4fa6 url: https://src.opensuse.org/python-interpreters/python315.git -revision: 699574482616cd14535b890206a88920be7ee5f0f66abeece2826d05df83d092 +revision: 3312e86ee4a2708afdaa23ebdcf981dbd3c3306d7f68bb406a9e3f321c0a4fa6 projectscmsync: https://src.opensuse.org/python-interpreters/_ObsPrj ++++++ build.specials.obscpio ++++++ --- old/.gitignore 2026-01-29 14:06:45.000000000 +0100 +++ new/.gitignore 2026-02-04 22:23:01.000000000 +0100 @@ -1,4 +1,5 @@ *.obscpio +*.orig *.osc _build.* .pbuild ++++++ 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-04 22:23:01.000000000 +0100 @@ -0,0 +1,6 @@ +*.obscpio +*.orig +*.osc +_build.* +.pbuild +python315-*-build/
