Security fixes for CVE-2026-0865, CVE-2025-15366 and CVE-2025-15367

This commit is contained in:
Tomáš Hrnčiar 2026-02-09 10:38:43 +01:00
commit e0dac6a2c5
4 changed files with 241 additions and 1 deletions

90
00473-cve-2026-0865.patch Normal file
View file

@ -0,0 +1,90 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Seth Michael Larson <seth@python.org>
Date: Sat, 17 Jan 2026 11:46:21 -0600
Subject: 00473: CVE-2026-0865
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
---
Lib/test/support/__init__.py | 7 +++++++
Lib/test/test_wsgiref.py | 12 +++++++++++-
Lib/wsgiref/headers.py | 3 +++
.../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
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 0d3b9634f1..d0492fe191 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -2157,3 +2157,10 @@ def adjust_int_max_str_digits(max_digits):
yield
finally:
sys.set_int_max_str_digits(current)
+
+
+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"]
diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py
index 42094f4677..01ca51ba45 100644
--- a/Lib/test/test_wsgiref.py
+++ b/Lib/test/test_wsgiref.py
@@ -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.support import warnings_helper
from test.test_httpservers import NoLogRequestHandler
from unittest import TestCase
@@ -527,6 +527,16 @@ def testExtras(self):
'\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"""
diff --git a/Lib/wsgiref/headers.py b/Lib/wsgiref/headers.py
index fab851c5a4..fd98e85d75 100644
--- a/Lib/wsgiref/headers.py
+++ b/Lib/wsgiref/headers.py
@@ -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 __init__(self, headers=None):
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)))
diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst
new file mode 100644
index 0000000000..44bd0b2705
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst
@@ -0,0 +1,2 @@
+Reject C0 control characters within wsgiref.headers.Headers fields, values,
+and parameters.

View file

@ -0,0 +1,61 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Seth Michael Larson <seth@python.org>
Date: Tue, 20 Jan 2026 14:45:42 -0600
Subject: 00474: CVE-2025-15366
gh-143921: Reject control characters in IMAP commands
(cherry-picked from commit 6262704b134db2a4ba12e85ecfbd968534f28b45)
---
Lib/imaplib.py | 4 +++-
Lib/test/test_imaplib.py | 6 ++++++
.../Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst | 1 +
3 files changed, 10 insertions(+), 1 deletion(-)
create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst
diff --git a/Lib/imaplib.py b/Lib/imaplib.py
index 54122f985b..9ab8e43bbf 100644
--- a/Lib/imaplib.py
+++ b/Lib/imaplib.py
@@ -132,7 +132,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:
@@ -994,6 +994,8 @@ def _command(self, name, *args):
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
diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py
index f817707743..9ce59b3040 100644
--- a/Lib/test/test_imaplib.py
+++ b/Lib/test/test_imaplib.py
@@ -505,6 +505,12 @@ def test_login(self):
self.assertEqual(data[0], b'LOGIN completed')
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')
+
def test_logout(self):
client, _ = self._setup(SimpleIMAPHandler)
typ, data = client.login('user', 'pass')
diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst
new file mode 100644
index 0000000000..4e13fe92bc
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst
@@ -0,0 +1 @@
+Reject control characters in IMAP commands.

View file

@ -0,0 +1,61 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Seth Michael Larson <seth@python.org>
Date: Tue, 20 Jan 2026 14:46:32 -0600
Subject: 00475: CVE-2025-15367
gh-143923: Reject control characters in POP3 commands
(cherry-picked from commit b234a2b67539f787e191d2ef19a7cbdce32874e7)
---
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 0f8587317c..f563030f7f 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 1220ca32ef..2655e366fd 100644
--- a/Lib/test/test_poplib.py
+++ b/Lib/test/test_poplib.py
@@ -12,6 +12,7 @@
import unittest
from unittest import TestCase, skipUnless
from test import support as test_support
+from test.support import control_characters_c0
from test.support import hashlib_helper
from test.support import socket_helper
from test.support import threading_helper
@@ -365,6 +366,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 0000000000..3cde4df3e0
--- /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.

View file

@ -17,7 +17,7 @@ URL: https://www.python.org/
#global prerel ...
%global upstream_version %{general_version}%{?prerel}
Version: %{general_version}%{?prerel:~%{prerel}}
Release: 3%{?dist}
Release: 4%{?dist}
License: Python-2.0.1
@ -350,6 +350,31 @@ Patch452: 00452-properly-apply-exported-cflags-for-dtrace-systemtap-builds.patch
# stressed on OpenSSL 3.5.
Patch462: 00462-fix-pyssl_seterror-handling-ssl_error_syscall.patch
# 00473 # e0df4af4663a200a370a7c7b2391588396bcf20f
# CVE-2026-0865
#
# 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
Patch473: 00473-cve-2026-0865.patch
# 00474 # 837ddca0372fa87ff9cee47142200caa21e77def
# CVE-2025-15366
#
# gh-143921: Reject control characters in IMAP commands
#
# (cherry-picked from commit 6262704b134db2a4ba12e85ecfbd968534f28b45)
Patch474: 00474-cve-2025-15366.patch
# 00475 # 3748209a316662d4e85981ca1a7418547a1d25c6
# CVE-2025-15367
#
# gh-143923: Reject control characters in POP3 commands
#
# (cherry-picked from commit b234a2b67539f787e191d2ef19a7cbdce32874e7)
Patch475: 00475-cve-2025-15367.patch
# (New patches go here ^^^)
#
# When adding new patches to "python" and "python3" in Fedora, EL, etc.,
@ -1649,6 +1674,9 @@ CheckPython optimized
# ======================================================
%changelog
* Mon Feb 09 2026 Tomáš Hrnčiar <thrnciar@redhat.com> - 3.10.19-4
- Security fixes for CVE-2026-0865, CVE-2025-15366 and CVE-2025-15367
* Sat Jan 17 2026 Fedora Release Engineering <releng@fedoraproject.org> - 3.10.19-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild