]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-143921: Reject NUL, CR and LF in IMAP commands (GH-143922, GH-153067) ...
authorSerhiy Storchaka <storchaka@gmail.com>
Tue, 7 Jul 2026 18:38:25 +0000 (21:38 +0300)
committerGitHub <noreply@github.com>
Tue, 7 Jul 2026 18:38:25 +0000 (18:38 +0000)
Combined backport of GH-143922, which rejected all control characters,
and GH-153067, which narrowed the check to NUL, CR and LF.  Other
control characters are valid in quoted strings and are sent quoted.

(cherry picked from commit 6262704b134db2a4ba12e85ecfbd968534f28b45)
(cherry picked from commit d0921efb665aff26b378f495e5ff84f7e3fe649d)
(cherry picked from commit 298182272a740ce2016aee2f54acbd0bba1944c1)

Co-authored-by: Seth Michael Larson <seth@python.org>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Lib/imaplib.py
Lib/test/test_imaplib.py
Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst [new file with mode: 0644]

index 503e3c9cb8b777011da7a177c722f9b5d55f6cb9..0223a4ad9e2b027305cbb043182e7b5790d0c326 100644 (file)
@@ -132,6 +132,9 @@ Untagged_status = re.compile(
 # We compile these in _mode_xxx.
 _Literal = br'.*{(?P<size>\d+)}$'
 _Untagged_status = br'\* (?P<data>\d+) (?P<type>[A-Z-]+)( (?P<data2>.*))?'
+# Only NUL, CR and LF are unsafe (they cannot be represented even in
+# a quoted string); other control characters are sent quoted.
+_control_chars = re.compile(b'[\x00\r\n]')
 _non_astring_char = re.compile(br'[(){ \x00-\x1f\x7f-\xff%*\\"]')
 _non_list_char = re.compile(br'[(){ \x00-\x1f\x7f-\xff\\"]')
 _quoted = re.compile(br'"(?:[^"\\]|\\.)*+"')
@@ -1047,6 +1050,8 @@ class IMAP4:
             if arg is None: continue
             if isinstance(arg, str):
                 arg = bytes(arg, self._encoding)
+            if _control_chars.search(arg):
+                raise ValueError("NUL, CR and LF not allowed in commands")
             data = data + b' ' + arg
 
         literal = self.literal
index 9c1dcb1e299bf737a7dc463fd52ff6d1b16f959b..49a8c1a1b817c82d1c0e1bcbb2b9182767c18013 100644 (file)
@@ -1626,6 +1626,22 @@ class NewIMAPTestsMixin:
         with self.assertRaises(AttributeError):
             client.NONEXISTENT
 
+    def test_control_characters(self):
+        client, server = self._setup(SimpleIMAPHandler)
+        client.login('user', 'pass')
+        for c in '\0\r\n':
+            with self.assertRaises(ValueError):
+                client.select(f'a{c}b')
+        # Other control characters are valid in a quoted string and can
+        # occur in mailbox names returned by the server, so the client
+        # must be able to send them back.
+        for c in support.control_characters_c0():
+            if c in '\0\r\n':
+                continue
+            typ, _ = client.select(f'a{c}b')
+            self.assertEqual(typ, 'OK')
+            self.assertEqual(server.is_selected, [f'"a{c}b"'])
+
 
 class NewIMAPTests(NewIMAPTestsMixin, unittest.TestCase):
     imap_class = imaplib.IMAP4
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 (file)
index 0000000..de62e02
--- /dev/null
@@ -0,0 +1,2 @@
+Reject NUL, CR and LF characters in IMAP commands. Other control
+characters are allowed and sent quoted.