From 70db7ff339d050db15eca896bb27d632e7a0ad7c8db7c76ed01235fe26f1762a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= Date: Tue, 27 Jan 2026 14:31:46 +0100 Subject: [PATCH 1/4] doc: mention that we have already fixed also bsc#1257181 --- python314.changes | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python314.changes b/python314.changes index da22df2..71bbd59 100644 --- a/python314.changes +++ b/python314.changes @@ -4672,7 +4672,8 @@ Sat Sep 7 15:36:03 UTC 2024 - Matej Cepl 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.; CVE-2024-6923, bsc#1228780) + Petr Viktorin in gh-121650.; CVE-2024-6923, bsc#1228780, + bsc#1257181) - gh-121723: Make logging.config.dictConfig() accept any object implementing the Queue public API. See the queue configuration section for details. Patch by Bénédikt Tran. From faa9dd3a196070b5cfef2b12dc0bbe6cb0d5b7c7a0decdda9ba1dd61937f2147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= Date: Tue, 27 Jan 2026 17:58:02 +0100 Subject: [PATCH 2/4] Add CVE-2024-6923-follow-up-EOL-email-headers.patch It is a follow-up to the previous fix of CVE-2024-6923 further encoding EOL possibly hidden in email headers (bsc#1257181). --- ...024-6923-follow-up-EOL-email-headers.patch | 104 ++++++++++++++++++ python314.changes | 7 ++ python314.spec | 4 + 3 files changed, 115 insertions(+) create mode 100644 CVE-2024-6923-follow-up-EOL-email-headers.patch diff --git a/CVE-2024-6923-follow-up-EOL-email-headers.patch b/CVE-2024-6923-follow-up-EOL-email-headers.patch new file mode 100644 index 0000000..0491c18 --- /dev/null +++ b/CVE-2024-6923-follow-up-EOL-email-headers.patch @@ -0,0 +1,104 @@ +From 5a8bfd878f086e28f0849bbc3970ad92f6ba37dc Mon Sep 17 00:00:00 2001 +From: Seth Michael Larson +Date: Fri, 23 Jan 2026 08:59:35 -0600 +Subject: [PATCH] gh-144125: email: verify headers are sound in BytesGenerator + (cherry picked from commit 052e55e7d44718fe46cbba0ca995cb8fcc359413) + +Co-authored-by: Seth Michael Larson +Co-authored-by: Denis Ledoux +Co-authored-by: Denis Ledoux <5822488+beledouxdenis@users.noreply.github.com> +Co-authored-by: Petr Viktorin <302922+encukou@users.noreply.github.com> +Co-authored-by: Bas Bloemsaat <1586868+basbloemsaat@users.noreply.github.com> +--- + Lib/email/generator.py | 12 +++++++++- + Lib/test/test_email/test_generator.py | 4 ++- + Lib/test/test_email/test_policy.py | 6 ++++- + Misc/NEWS.d/next/Security/2026-01-21-12-34-05.gh-issue-144125.TAz5uo.rst | 4 +++ + 4 files changed, 23 insertions(+), 3 deletions(-) + create mode 100644 Misc/NEWS.d/next/Security/2026-01-21-12-34-05.gh-issue-144125.TAz5uo.rst + +Index: Python-3.14.2/Lib/email/generator.py +=================================================================== +--- Python-3.14.2.orig/Lib/email/generator.py 2026-01-28 22:15:51.075267925 +0100 ++++ Python-3.14.2/Lib/email/generator.py 2026-01-28 22:15:56.251194626 +0100 +@@ -22,6 +22,7 @@ + NLCRE = re.compile(r'\r\n|\r|\n') + fcre = re.compile(r'^From ', re.MULTILINE) + NEWLINE_WITHOUT_FWSP = re.compile(r'\r\n[^ \t]|\r[^ \n\t]|\n[^ \t]') ++NEWLINE_WITHOUT_FWSP_BYTES = re.compile(br'\r\n[^ \t]|\r[^ \n\t]|\n[^ \t]') + + + class Generator: +@@ -429,7 +430,16 @@ + # This is almost the same as the string version, except for handling + # strings with 8bit bytes. + for h, v in msg.raw_items(): +- self._fp.write(self.policy.fold_binary(h, v)) ++ folded = self.policy.fold_binary(h, v) ++ if self.policy.verify_generated_headers: ++ linesep = self.policy.linesep.encode() ++ if not folded.endswith(linesep): ++ raise HeaderWriteError( ++ f'folded header does not end with {linesep!r}: {folded!r}') ++ if NEWLINE_WITHOUT_FWSP_BYTES.search(folded.removesuffix(linesep)): ++ raise HeaderWriteError( ++ f'folded header contains newline: {folded!r}') ++ self._fp.write(folded) + # A blank line always separates headers from body + self.write(self._NL) + +Index: Python-3.14.2/Lib/test/test_email/test_generator.py +=================================================================== +--- Python-3.14.2.orig/Lib/test/test_email/test_generator.py 2026-01-28 22:15:52.693627763 +0100 ++++ Python-3.14.2/Lib/test/test_email/test_generator.py 2026-01-28 22:15:56.251344799 +0100 +@@ -313,7 +313,7 @@ + self.assertEqual(s.getvalue(), self.typ(expected)) + + def test_verify_generated_headers(self): +- """gh-121650: by default the generator prevents header injection""" ++ # gh-121650: by default the generator prevents header injection + class LiteralHeader(str): + name = 'Header' + def fold(self, **kwargs): +@@ -334,6 +334,8 @@ + + with self.assertRaises(email.errors.HeaderWriteError): + message.as_string() ++ with self.assertRaises(email.errors.HeaderWriteError): ++ message.as_bytes() + + + class TestBytesGenerator(TestGeneratorBase, TestEmailBase): +Index: Python-3.14.2/Lib/test/test_email/test_policy.py +=================================================================== +--- Python-3.14.2.orig/Lib/test/test_email/test_policy.py 2026-01-28 22:15:52.703671956 +0100 ++++ Python-3.14.2/Lib/test/test_email/test_policy.py 2026-01-28 22:15:56.251499922 +0100 +@@ -296,7 +296,7 @@ + policy.fold("Subject", subject) + + def test_verify_generated_headers(self): +- """Turning protection off allows header injection""" ++ # Turning protection off allows header injection + policy = email.policy.default.clone(verify_generated_headers=False) + for text in ( + 'Header: Value\r\nBad: Injection\r\n', +@@ -319,6 +319,10 @@ + message.as_string(), + f"{text}\nBody", + ) ++ self.assertEqual( ++ message.as_bytes(), ++ f"{text}\nBody".encode(), ++ ) + + # XXX: Need subclassing tests. + # For adding subclassed objects, make sure the usual rules apply (subclass +Index: Python-3.14.2/Misc/NEWS.d/next/Security/2026-01-21-12-34-05.gh-issue-144125.TAz5uo.rst +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ Python-3.14.2/Misc/NEWS.d/next/Security/2026-01-21-12-34-05.gh-issue-144125.TAz5uo.rst 2026-01-28 22:15:56.251667056 +0100 +@@ -0,0 +1,4 @@ ++:mod:`~email.generator.BytesGenerator` will now refuse to serialize (write) headers ++that are unsafely folded or delimited; see ++:attr:`~email.policy.Policy.verify_generated_headers`. (Contributed by Bas ++Bloemsaat and Petr Viktorin in :gh:`121650`). diff --git a/python314.changes b/python314.changes index 71bbd59..9059a6a 100644 --- a/python314.changes +++ b/python314.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Thu Jan 29 12:58:15 UTC 2026 - Matej Cepl + +- Add CVE-2024-6923-follow-up-EOL-email-headers.patch which is + a follow-up to the previous fix of CVE-2024-6923 further + encoding EOL possibly hidden in email headers (bsc#1257181). + ------------------------------------------------------------------- Thu Dec 11 17:37:09 UTC 2025 - Matej Cepl diff --git a/python314.spec b/python314.spec index 59f8074..fa83ece 100644 --- a/python314.spec +++ b/python314.spec @@ -224,6 +224,10 @@ Patch41: bsc1243155-sphinx-non-determinism.patch Patch44: gh138131-exclude-pycache-from-digest.patch # PATCH-FIX-OPENSUSE gh139257-Support-docutils-0.22.patch gh#python/cpython#139257 daniel.garcia@suse.com Patch45: gh139257-Support-docutils-0.22.patch +# PATCH-FIX-UPSTREAM CVE-2024-6923-follow-up-EOL-email-headers.patch bsc#1257181 mcepl@suse.com +# Encode newlines in headers when using ByteGenerator +# patch from gh#python/cpython#144125 +Patch46: CVE-2024-6923-follow-up-EOL-email-headers.patch #### Python 3.14 DEVELOPMENT PATCHES BuildRequires: autoconf-archive BuildRequires: automake From 3a0658eda43cd8c3eeac0838a1b2980fc4402a050f83f8c3a59b63bcc8e5a7f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= Date: Thu, 29 Jan 2026 13:46:47 +0100 Subject: [PATCH 3/4] Add CVE-2025-11468-email-hdr-fold-comment.patch Preserving parens when folding comments in email headers (bsc#1257029, CVE-2025-11468). --- CVE-2025-11468-email-hdr-fold-comment.patch | 109 ++++++++++++++++++++ python314.changes | 3 + python314.spec | 5 +- 3 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 CVE-2025-11468-email-hdr-fold-comment.patch diff --git a/CVE-2025-11468-email-hdr-fold-comment.patch b/CVE-2025-11468-email-hdr-fold-comment.patch new file mode 100644 index 0000000..e9b79e3 --- /dev/null +++ b/CVE-2025-11468-email-hdr-fold-comment.patch @@ -0,0 +1,109 @@ +From df45bd1aafc3b6792d43661207d2b7eb3a14d214 Mon Sep 17 00:00:00 2001 +From: Seth Michael Larson +Date: Mon, 19 Jan 2026 06:38:22 -0600 +Subject: [PATCH] gh-143935: Email preserve parens when folding comments + (GH-143936) + +Fix a bug in the folding of comments when flattening an email message +using a modern email policy. Comments consisting of a very long sequence of +non-foldable characters could trigger a forced line wrap that omitted the +required leading space on the continuation line, causing the remainder of +the comment to be interpreted as a new header field. This enabled header +injection with carefully crafted inputs. +(cherry picked from commit 17d1490aa97bd6b98a42b1a9b324ead84e7fd8a2) + +Co-authored-by: Seth Michael Larson +Co-authored-by: Denis Ledoux +--- + Lib/email/_header_value_parser.py | 15 +++++++++++- + .../test_email/test__header_value_parser.py | 23 +++++++++++++++++++ + ...-01-16-14-40-31.gh-issue-143935.U2YtKl.rst | 6 +++++ + 3 files changed, 43 insertions(+), 1 deletion(-) + create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst + +diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py +index 68c2cf9585c5b4..51727688c059ed 100644 +--- a/Lib/email/_header_value_parser.py ++++ b/Lib/email/_header_value_parser.py +@@ -101,6 +101,12 @@ def make_quoted_pairs(value): + return str(value).replace('\\', '\\\\').replace('"', '\\"') + + ++def make_parenthesis_pairs(value): ++ """Escape parenthesis and backslash for use within a comment.""" ++ return str(value).replace('\\', '\\\\') \ ++ .replace('(', '\\(').replace(')', '\\)') ++ ++ + def quote_string(value): + escaped = make_quoted_pairs(value) + return f'"{escaped}"' +@@ -939,7 +945,7 @@ def value(self): + return ' ' + + def startswith_fws(self): +- return True ++ return self and self[0] in WSP + + + class ValueTerminal(Terminal): +@@ -2959,6 +2965,13 @@ def _refold_parse_tree(parse_tree, *, policy): + [ValueTerminal(make_quoted_pairs(p), 'ptext') + for p in newparts] + + [ValueTerminal('"', 'ptext')]) ++ if part.token_type == 'comment': ++ newparts = ( ++ [ValueTerminal('(', 'ptext')] + ++ [ValueTerminal(make_parenthesis_pairs(p), 'ptext') ++ if p.token_type == 'ptext' else p ++ for p in newparts] + ++ [ValueTerminal(')', 'ptext')]) + if not part.as_ew_allowed: + wrap_as_ew_blocked += 1 + newparts.append(end_ew_not_allowed) +diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py +index 426ec4644e3096..e28fe3892015b9 100644 +--- a/Lib/test/test_email/test__header_value_parser.py ++++ b/Lib/test/test_email/test__header_value_parser.py +@@ -3294,6 +3294,29 @@ def test_address_list_with_specials_in_long_quoted_string(self): + with self.subTest(to=to): + self._test(parser.get_address_list(to)[0], folded, policy=policy) + ++ def test_address_list_with_long_unwrapable_comment(self): ++ policy = self.policy.clone(max_line_length=40) ++ cases = [ ++ # (to, folded) ++ ('(loremipsumdolorsitametconsecteturadipi)', ++ '(loremipsumdolorsitametconsecteturadipi)\n'), ++ ('(loremipsumdolorsitametconsecteturadipi)', ++ '(loremipsumdolorsitametconsecteturadipi)\n'), ++ ('(loremipsum dolorsitametconsecteturadipi)', ++ '(loremipsum dolorsitametconsecteturadipi)\n'), ++ ('(loremipsum dolorsitametconsecteturadipi)', ++ '(loremipsum\n dolorsitametconsecteturadipi)\n'), ++ ('(Escaped \\( \\) chars \\\\ in comments stay escaped)', ++ '(Escaped \\( \\) chars \\\\ in comments stay\n escaped)\n'), ++ ('((loremipsum)(loremipsum)(loremipsum)(loremipsum))', ++ '((loremipsum)(loremipsum)(loremipsum)(loremipsum))\n'), ++ ('((loremipsum)(loremipsum)(loremipsum) (loremipsum))', ++ '((loremipsum)(loremipsum)(loremipsum)\n (loremipsum))\n'), ++ ] ++ for (to, folded) in cases: ++ with self.subTest(to=to): ++ self._test(parser.get_address_list(to)[0], folded, policy=policy) ++ + # XXX Need tests with comments on various sides of a unicode token, + # and with unicode tokens in the comments. Spaces inside the quotes + # currently don't do the right thing. +diff --git a/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst b/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst +new file mode 100644 +index 00000000000000..c3d864936884ac +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst +@@ -0,0 +1,6 @@ ++Fixed a bug in the folding of comments when flattening an email message ++using a modern email policy. Comments consisting of a very long sequence of ++non-foldable characters could trigger a forced line wrap that omitted the ++required leading space on the continuation line, causing the remainder of ++the comment to be interpreted as a new header field. This enabled header ++injection with carefully crafted inputs. diff --git a/python314.changes b/python314.changes index 9059a6a..896d0b5 100644 --- a/python314.changes +++ b/python314.changes @@ -4,6 +4,9 @@ Thu Jan 29 12:58:15 UTC 2026 - Matej Cepl - Add CVE-2024-6923-follow-up-EOL-email-headers.patch which is a follow-up to the previous fix of CVE-2024-6923 further encoding EOL possibly hidden in email headers (bsc#1257181). +- Add CVE-2025-11468-email-hdr-fold-comment.patch preserving + parens when folding comments in email headers (bsc#1257029, + CVE-2025-11468). ------------------------------------------------------------------- Thu Dec 11 17:37:09 UTC 2025 - Matej Cepl diff --git a/python314.spec b/python314.spec index fa83ece..86f52fc 100644 --- a/python314.spec +++ b/python314.spec @@ -228,7 +228,10 @@ Patch45: gh139257-Support-docutils-0.22.patch # Encode newlines in headers when using ByteGenerator # patch from gh#python/cpython#144125 Patch46: CVE-2024-6923-follow-up-EOL-email-headers.patch -#### Python 3.14 DEVELOPMENT PATCHES +# PATCH-FIX-UPSTREAM CVE-2025-11468-email-hdr-fold-comment.patch bsc#1257029 mcepl@suse.com +# Email preserve parens when folding comments +Patch47: CVE-2025-11468-email-hdr-fold-comment.patch +#### Python 3.14 END OF PATCHES BuildRequires: autoconf-archive BuildRequires: automake BuildRequires: fdupes From 902b37d5bd4591c9e42b56cd73605817bb564242e61e44185e5f8f22a2223fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Cepl?= Date: Thu, 29 Jan 2026 14:05:31 +0100 Subject: [PATCH 4/4] Add CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch Reject control characters in http cookies (bsc#1257031, CVE-2026-0672). --- ...6-0672-http-hdr-inject-cookie-Morsel.patch | 183 ++++++++++++++++++ python314.changes | 3 + python314.spec | 3 + 3 files changed, 189 insertions(+) create mode 100644 CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch 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..71b1f94 --- /dev/null +++ b/CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch @@ -0,0 +1,183 @@ +From 2bb0ca857e7d2593da6f6936187465a49a63c2d5 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.14.2/Doc/library/http.cookies.rst +=================================================================== +--- Python-3.14.2.orig/Doc/library/http.cookies.rst 2025-12-05 17:49:16.000000000 +0100 ++++ Python-3.14.2/Doc/library/http.cookies.rst 2026-01-29 14:10:49.541240012 +0100 +@@ -292,9 +292,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.14.2/Lib/http/cookies.py +=================================================================== +--- Python-3.14.2.orig/Lib/http/cookies.py 2026-01-29 14:10:43.692250194 +0100 ++++ Python-3.14.2/Lib/http/cookies.py 2026-01-29 14:10:49.541387681 +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. +@@ -294,12 +303,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): +@@ -335,6 +348,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 +@@ -488,7 +504,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.14.2/Lib/test/test_http_cookies.py +=================================================================== +--- Python-3.14.2.orig/Lib/test/test_http_cookies.py 2026-01-29 14:10:45.256577882 +0100 ++++ Python-3.14.2/Lib/test/test_http_cookies.py 2026-01-29 14:10:49.541565806 +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', +@@ -571,6 +571,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.14.2/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.14.2/Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst 2026-01-29 14:10:49.541701772 +0100 +@@ -0,0 +1 @@ ++Reject control characters in :class:`http.cookies.Morsel` fields and values. diff --git a/python314.changes b/python314.changes index 896d0b5..f1a954a 100644 --- a/python314.changes +++ b/python314.changes @@ -7,6 +7,9 @@ Thu Jan 29 12:58:15 UTC 2026 - Matej Cepl - Add CVE-2025-11468-email-hdr-fold-comment.patch preserving parens when folding comments in email headers (bsc#1257029, CVE-2025-11468). +- Add CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch, which + rejects control characters in http cookies (bsc#1257031, + CVE-2026-0672). ------------------------------------------------------------------- Thu Dec 11 17:37:09 UTC 2025 - Matej Cepl diff --git a/python314.spec b/python314.spec index 86f52fc..bbc6ae6 100644 --- a/python314.spec +++ b/python314.spec @@ -231,6 +231,9 @@ Patch46: CVE-2024-6923-follow-up-EOL-email-headers.patch # PATCH-FIX-UPSTREAM CVE-2025-11468-email-hdr-fold-comment.patch bsc#1257029 mcepl@suse.com # Email preserve parens when folding comments 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 #### Python 3.14 END OF PATCHES BuildRequires: autoconf-archive BuildRequires: automake