From 152a6ee9c619debd8e78d95ad484f2c60b8670b57cbcbe0cf045abe2222d5be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= Date: Tue, 10 Feb 2026 23:12:15 +0100 Subject: [PATCH] Fix eight bugs (mostly rejecting ctrl chars in various protocols) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 CVE-2025-13836: to prevent reading an HTTP response from 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 - 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-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. - 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). - gh-120495: Fix incorrect exception handling in Tab Nanny. Patch by Wulian233. 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 - 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-121871: Documentation HTML varies from timestamp. Patch by Bernhard M. Wiedemann (bsc#1227999). - gh-122029: Emit c_call events in sys.setprofile() when a PyMethodObject pointing to a PyCFunction is called. modification of a list object, where one thread assigns a slice and another clears it. bytes and bytearray objects when using protocol version 5. Patch by Bénédikt Tran. --- CVE-2025-12781-b64decode-alt-chars.patch | 193 ++++++++++++++++++ CVE-2025-15282-urllib-ctrl-chars.patch | 64 ++++++ CVE-2025-15366-imap-ctrl-chars.patch | 38 ++++ CVE-2025-15367-poplib-ctrl-chars.patch | 83 ++++++++ ...6-0672-http-hdr-inject-cookie-Morsel.patch | 183 +++++++++++++++++ CVE-2026-0865-wsgiref-ctrl-chars.patch | 96 +++++++++ python312.changes | 121 ++++++----- python312.spec | 15 ++ 8 files changed, 742 insertions(+), 51 deletions(-) create mode 100644 CVE-2025-12781-b64decode-alt-chars.patch create mode 100644 CVE-2025-15282-urllib-ctrl-chars.patch create mode 100644 CVE-2025-15366-imap-ctrl-chars.patch create mode 100644 CVE-2025-15367-poplib-ctrl-chars.patch create mode 100644 CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch create mode 100644 CVE-2026-0865-wsgiref-ctrl-chars.patch diff --git a/CVE-2025-12781-b64decode-alt-chars.patch b/CVE-2025-12781-b64decode-alt-chars.patch new file mode 100644 index 0000000..bbe241f --- /dev/null +++ b/CVE-2025-12781-b64decode-alt-chars.patch @@ -0,0 +1,193 @@ +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 | 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. diff --git a/CVE-2025-15282-urllib-ctrl-chars.patch b/CVE-2025-15282-urllib-ctrl-chars.patch new file mode 100644 index 0000000..3e78e8f --- /dev/null +++ b/CVE-2025-15282-urllib-ctrl-chars.patch @@ -0,0 +1,64 @@ +From f336af1c4b103297de1322bbe00f920f3e58b899 Mon Sep 17 00:00:00 2001 +From: Seth Michael Larson +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 +--- + 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. diff --git a/CVE-2025-15366-imap-ctrl-chars.patch b/CVE-2025-15366-imap-ctrl-chars.patch new file mode 100644 index 0000000..e42abab --- /dev/null +++ b/CVE-2025-15366-imap-ctrl-chars.patch @@ -0,0 +1,38 @@ +From 7485ee5e2cf81d3e5ad0d9c3be73cecd2ab4eec7 Mon Sep 17 00:00:00 2001 +From: Seth Michael Larson +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\d+)}$' + _Untagged_status = br'\* (?P\d+) (?P[A-Z-]+)( (?P.*))?' +- ++_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. diff --git a/CVE-2025-15367-poplib-ctrl-chars.patch b/CVE-2025-15367-poplib-ctrl-chars.patch new file mode 100644 index 0000000..e9ec422 --- /dev/null +++ b/CVE-2025-15367-poplib-ctrl-chars.patch @@ -0,0 +1,83 @@ +From b6f733b285b1c4f27dacb5c2e1f292c914e8b933 Mon Sep 17 00:00:00 2001 +From: Seth Michael Larson +Date: Fri, 16 Jan 2026 10:54:09 -0600 +Subject: [PATCH 1/2] Add 'test.support' fixture for C0 control characters + +--- + Lib/test/support/__init__.py | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py +index 3a639497fa1272..9c113a6c137e52 100644 +--- a/Lib/test/support/__init__.py ++++ b/Lib/test/support/__init__.py +@@ -3303,3 +3303,10 @@ def linked_to_musl(): + return _linked_to_musl + _linked_to_musl = tuple(map(int, version.split('.'))) + return _linked_to_musl ++ ++ ++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"] + +From 58591540fc2140bd1a79e292af1ceea607ba957a Mon Sep 17 00:00:00 2001 +From: Seth Michael Larson +Date: Tue, 30 Dec 2025 11:03:02 -0600 +Subject: [PATCH 2/2] gh-143923: Reject control characters in POP3 commands + +--- + Lib/poplib.py | 2 ++ + Lib/test/test_poplib.py | 8 ++++++++ + .../2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst | 1 + + 3 files changed, 11 insertions(+) + create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst + +diff --git a/Lib/poplib.py b/Lib/poplib.py +index 4469bff44b4c45..b97274c5c32ee6 100644 +--- a/Lib/poplib.py ++++ b/Lib/poplib.py +@@ -122,6 +122,8 @@ def _putline(self, line): + 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) + + +diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py +index ef2da97f86734a..18ca7cb556836e 100644 +--- a/Lib/test/test_poplib.py ++++ b/Lib/test/test_poplib.py +@@ -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 @@ def test_quit(self): + 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() +diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst +new file mode 100644 +index 00000000000000..3cde4df3e0069f +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst +@@ -0,0 +1 @@ ++Reject control characters in POP3 commands. diff --git a/CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch b/CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch new file mode 100644 index 0000000..1ce4e2f --- /dev/null +++ b/CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch @@ -0,0 +1,183 @@ +From 9729bdf210967c806f3364c76663fc2ade58e389 Mon Sep 17 00:00:00 2001 +From: Seth Michael Larson +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 +Co-authored-by: Bartosz Sławecki +Co-authored-by: sobolevn +--- + 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': "", + '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': '''''', +- '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': '''''', ++ '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. diff --git a/CVE-2026-0865-wsgiref-ctrl-chars.patch b/CVE-2026-0865-wsgiref-ctrl-chars.patch new file mode 100644 index 0000000..d189998 --- /dev/null +++ b/CVE-2026-0865-wsgiref-ctrl-chars.patch @@ -0,0 +1,96 @@ +From 03a7342c9e2bbdab20a6d882bf334608dc7a5d4b Mon Sep 17 00:00:00 2001 +From: "Gregory P. Smith" <68491+gpshead@users.noreply.github.com> +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 <68491+gpshead@users.noreply.github.com> +Co-authored-by: Seth Michael Larson +--- + 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. diff --git a/python312.changes b/python312.changes index 5e96861..b67b7a6 100644 --- a/python312.changes +++ b/python312.changes @@ -1,22 +1,43 @@ ------------------------------------------------------------------- Fri Feb 6 00:07:20 CET 2026 - Matej Cepl - -- Add CVE-2025-11468-email-hdr-fold-comment.patch (bsc#1257029, - CVE-2025-11468) to preserve parens when folding comments. + +- 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 ------------------------------------------------------------------- Thu Dec 18 10:33:44 UTC 2025 - Matej Cepl -- 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 a server, if no read amount is specified, with using - 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 ------------------------------------------------------------------- Wed Nov 19 19:21:41 UTC 2025 - Matej Cepl @@ -1214,25 +1235,23 @@ Wed Aug 7 18:05:57 UTC 2024 - Matej Cepl - Tests - gh-59022: Add tests for pkgutil.extend_path(). Patch by Andreas Stocker. - - 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. - gh-121084: Fix test_typing random leaks. Clear typing ABC caches when running tests for refleaks (-R option): call _abc_caches_clear() on typing abstract classes and their subclasses. 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. + - 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. - Security - gh-121957: Fixed missing audit events around interactive use of Python, now also properly firing for python -i, as @@ -1255,12 +1274,12 @@ Wed Aug 7 18:05:57 UTC 2024 - Matej Cepl filecmp.dircmp and filecmp.cmpfiles(). Patch by Bénédikt Tran. - gh-122311: Fix some error messages in pickle. - - 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; bsc#1257181, CVE-2026-1299). + - 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). - gh-122332: Fixed segfault with asyncio.Task.get_coro() when using an eager task factory. - gh-122170: Handle ValueErrors raised by os.stat() in @@ -1297,8 +1316,8 @@ Wed Aug 7 18:05:57 UTC 2024 - Matej Cepl even when the command is from cmdqueue. - gh-120732: Fix name passing to unittest.mock.Mock object when using unittest.mock.create_autospec(). - - gh-120495: Fix incorrect exception handling in Tab - Nanny. Patch by Wulian233. + - gh-120495: Fix incorrect exception handling in Tab Nanny. + Patch by Wulian233. - gh-120343: Fix column offset reporting for tokens that come after multiline f-strings in the tokenize module. - gh-119600: Fix unittest.mock.patch() to not read attributes @@ -1307,9 +1326,9 @@ Wed Aug 7 18:05:57 UTC 2024 - Matej Cepl - gh-120289: Fixed the use-after-free issue in cProfile by disallowing disable() and clear() in external timers. - gh-114053: Fix edge-case bug where typing.get_type_hints() - 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 enabled. Patch by Alex Waygood. - gh-114053: Fix erroneous NameError when calling inspect.get_annotations() with eval_str=True` on a class @@ -1334,11 +1353,11 @@ Wed Aug 7 18:05:57 UTC 2024 - Matej Cepl - gh-112672: Support building tkinter with Tcl 9.0. - gh-65454: unittest.mock.Mock.attach_mock() no longer triggers a call to a PropertyMock being attached. - - 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 describes unconditionally returning True in a future version rather than raising an exception in Python 3.14. - gh-119506: Fix io.TextIOWrapper.write() method breaks @@ -1367,16 +1386,16 @@ Wed Aug 7 18:05:57 UTC 2024 - Matej Cepl multiprocessing.Queue.empty() and multiprocessing.SimpleQueue.empty() on closed queues. Patch by Bénédikt Tran. - - 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). - Core and Builtins - gh-122208: Dictionary watchers now only deliver the PyDict_EVENT_ADDED event when the insertion is in a known good state to succeed. - gh-122300: Preserve AST nodes for f-string with single-element format specifiers. Patch by Pablo Galindo - - 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. - gh-122026: Fix a bug that caused the tokenizer to not correctly identify mismatched parentheses inside f-strings in some situations. Patch by Pablo Galindo @@ -1393,11 +1412,11 @@ Wed Aug 7 18:05:57 UTC 2024 - Matej Cepl - gh-120384: Fix an array out of bounds crash in list_ass_subscript, which could be invoked via some specificly tailored input: including concurrent - 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. - gh-120380: Fix Python implementation of pickle.Pickler for - 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. - gh-93691: Fix source locations of instructions generated for the iterator of a for statement. - gh-120198: Fix a crash when multiple threads read and write diff --git a/python312.spec b/python312.spec index 222e77e..a89e5c1 100644 --- a/python312.spec +++ b/python312.spec @@ -207,6 +207,21 @@ Patch51: CVE-2025-13837-plistlib-mailicious-length.patch # PATCH-FIX-UPSTREAM CVE-2025-11468-email-hdr-fold-comment.patch bsc#1257029 mcepl@suse.com # 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 mcepl@suse.com +# 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 mcepl@suse.com +# 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 mcepl@suse.com +# 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 mcepl@suse.com +# 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 mcepl@suse.com +# Reject control characters in urllib +Patch57: CVE-2025-15282-urllib-ctrl-chars.patch ### END OF PATCHES BuildRequires: autoconf-archive BuildRequires: automake