diff --git a/CVE-2025-12781-b64decode-alt-chars.patch b/CVE-2025-12781-b64decode-alt-chars.patch new file mode 100644 index 0000000..df038f6 --- /dev/null +++ b/CVE-2025-12781-b64decode-alt-chars.patch @@ -0,0 +1,196 @@ +From f922c02c529d25d61aa9c28a8192639c1fce8d4d Mon Sep 17 00:00:00 2001 +From: Serhiy Storchaka +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 | 45 ++++++++-- + Misc/NEWS.d/next/Library/2025-11-06-12-03-29.gh-issue-125346.7Gfpgw.rst | 5 + + 4 files changed, 91 insertions(+), 17 deletions(-) + +Index: Python-3.14.2/Doc/library/base64.rst +=================================================================== +--- Python-3.14.2.orig/Doc/library/base64.rst 2025-12-05 17:49:16.000000000 +0100 ++++ Python-3.14.2/Doc/library/base64.rst 2026-02-03 18:10:52.115333313 +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.14.2/Lib/base64.py +=================================================================== +--- Python-3.14.2.orig/Lib/base64.py 2026-02-03 18:10:42.615516871 +0100 ++++ Python-3.14.2/Lib/base64.py 2026-02-03 18:10:52.115801314 +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.14.2/Lib/test/test_base64.py +=================================================================== +--- Python-3.14.2.orig/Lib/test/test_base64.py 2026-02-03 18:10:43.960993003 +0100 ++++ Python-3.14.2/Lib/test/test_base64.py 2026-02-03 18:10:52.116085599 +0100 +@@ -242,6 +242,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') +@@ -273,13 +292,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 test_b32encode(self): + eq = self.assertEqual +Index: Python-3.14.2/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.14.2/Misc/NEWS.d/next/Library/2025-11-06-12-03-29.gh-issue-125346.7Gfpgw.rst 2026-02-03 18:10:52.116411403 +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. diff --git a/python314.changes b/python314.changes index f1a954a..91cc934 100644 --- a/python314.changes +++ b/python314.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Tue Feb 3 15:39:21 UTC 2026 - Matej Cepl + +- 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. + ------------------------------------------------------------------- Thu Jan 29 12:58:15 UTC 2026 - Matej Cepl diff --git a/python314.spec b/python314.spec index bbc6ae6..c8e1f07 100644 --- a/python314.spec +++ b/python314.spec @@ -234,6 +234,9 @@ Patch47: 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 Patch48: 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 +Patch49: CVE-2025-12781-b64decode-alt-chars.patch #### Python 3.14 END OF PATCHES BuildRequires: autoconf-archive BuildRequires: automake