Compare commits
4 Commits
| Author | SHA256 | Date | |
|---|---|---|---|
|
9dafe030c1
|
|||
|
0ac3868be4
|
|||
|
e5855b89e8
|
|||
|
63187f7b8b
|
217
CVE-2025-12781-b64decode-alt-chars.patch
Normal file
217
CVE-2025-12781-b64decode-alt-chars.patch
Normal file
@@ -0,0 +1,217 @@
|
||||
From f922c02c529d25d61aa9c28a8192639c1fce8d4d Mon Sep 17 00:00:00 2001
|
||||
From: Serhiy Storchaka <storchaka@gmail.com>
|
||||
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.
|
||||
59
CVE-2025-15282-urllib-ctrl-chars.patch
Normal file
59
CVE-2025-15282-urllib-ctrl-chars.patch
Normal file
@@ -0,0 +1,59 @@
|
||||
From d8850aac54c234201966c66e83225564302cd15c Mon Sep 17 00:00:00 2001
|
||||
From: Seth Michael Larson <seth@python.org>
|
||||
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.
|
||||
56
CVE-2025-15366-imap-ctrl-chars.patch
Normal file
56
CVE-2025-15366-imap-ctrl-chars.patch
Normal file
@@ -0,0 +1,56 @@
|
||||
From 7485ee5e2cf81d3e5ad0d9c3be73cecd2ab4eec7 Mon Sep 17 00:00:00 2001
|
||||
From: Seth Michael Larson <seth@python.org>
|
||||
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.
|
||||
@@ -14,7 +14,7 @@ Subject: [PATCH 1/5] Add 'test.support' fixture for C0 control characters
|
||||
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 @@ Index: Python-3.15.0a3/Doc/library/http.cookies.rst
|
||||
>>> 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 @@ Index: Python-3.15.0a3/Lib/http/cookies.py
|
||||
__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 @@ Index: Python-3.15.0a3/Lib/test/support/__init__.py
|
||||
+ 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,6 +186,6 @@ Index: Python-3.15.0a3/Lib/test/test_http_cookies.py
|
||||
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.
|
||||
|
||||
68
CVE-2026-0865-wsgiref-hdrs-EOLs.patch
Normal file
68
CVE-2026-0865-wsgiref-hdrs-EOLs.patch
Normal file
@@ -0,0 +1,68 @@
|
||||
From e7f180b4c21576f52c08933a184d84dc4b47e00e Mon Sep 17 00:00:00 2001
|
||||
From: Seth Michael Larson <seth@python.org>
|
||||
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.
|
||||
@@ -1,3 +1,21 @@
|
||||
-------------------------------------------------------------------
|
||||
Wed Feb 4 00:53:37 UTC 2026 - Matej Cepl <mcepl@cepl.eu>
|
||||
|
||||
- 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-hdrs-EOLs.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.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Tue Jan 27 16:31:12 UTC 2026 - Matej Cepl <mcepl@cepl.eu>
|
||||
|
||||
|
||||
@@ -238,6 +238,18 @@ Patch45: CVE-2025-11468-email-hdr-fold-comment.patch
|
||||
# PATCH-FIX-UPSTREAM CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch bsc#1257031 mcepl@suse.com
|
||||
# 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 mcepl@suse.com
|
||||
# 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-hdrs-EOLs.patch bsc#1257042 mcepl@suse.com
|
||||
# Reject control characters in wsgiref.headers.Headers
|
||||
Patch48: CVE-2026-0865-wsgiref-hdrs-EOLs.patch
|
||||
# PATCH-FIX-UPSTREAM CVE-2025-15366-imap-ctrl-chars.patch bsc#1257044 mcepl@suse.com
|
||||
# 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 mcepl@suse.com
|
||||
# Reject control characters in wsgiref.headers.Headers
|
||||
Patch50: CVE-2025-15282-urllib-ctrl-chars.patch
|
||||
#### Python 3.15 DEVELOPMENT PATCHES
|
||||
BuildRequires: autoconf-archive
|
||||
BuildRequires: automake
|
||||
|
||||
Reference in New Issue
Block a user