Skip to content

Commit 7f613c0

Browse files
gh-143921: Narrow the control character check in imaplib commands
Only NUL, CR and LF are rejected now. Other control characters are valid in quoted strings and can occur in mailbox names returned by the server, so they are now accepted and sent quoted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 600e864 commit 7f613c0

3 files changed

Lines changed: 21 additions & 5 deletions

File tree

Lib/imaplib.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,9 @@
129129
# We compile these in _mode_xxx.
130130
_Literal = br'.*{(?P<size>\d+)}$'
131131
_Untagged_status = br'\* (?P<data>\d+) (?P<type>[A-Z-]+)( (?P<data2>.*))?'
132-
_control_chars = re.compile(b'[\x00-\x1F\x7F]')
132+
# Only NUL, CR and LF are unsafe (they cannot be represented even in
133+
# a quoted string); other control characters are sent quoted.
134+
_control_chars = re.compile(b'[\x00\r\n]')
133135
_non_astring_char = re.compile(br'[(){ \x00-\x1f\x7f-\xff%*\\"]')
134136
_non_list_char = re.compile(br'[(){ \x00-\x1f\x7f-\xff\\"]')
135137
_quoted = re.compile(br'"(?:[^"\\]|\\.)*+"')
@@ -1170,7 +1172,7 @@ def _command(self, name, *args):
11701172
if isinstance(arg, str):
11711173
arg = bytes(arg, self._encoding)
11721174
if _control_chars.search(arg):
1173-
raise ValueError("Control characters not allowed in commands")
1175+
raise ValueError("NUL, CR and LF not allowed in commands")
11741176
data = data + b' ' + arg
11751177

11761178
literal = self.literal

Lib/test/test_imaplib.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,10 +1741,20 @@ def test_xatom(self):
17411741
self.assertEqual(server.args, ['arg1', 'arg2'])
17421742

17431743
def test_control_characters(self):
1744-
client, _ = self._setup(SimpleIMAPHandler)
1745-
for c0 in support.control_characters_c0():
1744+
client, server = self._setup(SimpleIMAPHandler)
1745+
client.login('user', 'pass')
1746+
for c in '\0\r\n':
17461747
with self.assertRaises(ValueError):
1747-
client.login(f'user{c0}', 'pass')
1748+
client.select(f'a{c}b')
1749+
# Other control characters are valid in a quoted string and can
1750+
# occur in mailbox names returned by the server, so the client
1751+
# must be able to send them back.
1752+
for c in support.control_characters_c0():
1753+
if c in '\0\r\n':
1754+
continue
1755+
typ, _ = client.select(f'a{c}b')
1756+
self.assertEqual(typ, 'OK')
1757+
self.assertEqual(server.is_selected, [f'"a{c}b"'])
17481758

17491759
# property tests
17501760

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Narrow the control character check in :mod:`imaplib` commands: only NUL, CR
2+
and LF are now rejected. Other control characters are valid in quoted
3+
strings and can occur in mailbox names returned by the server, so they are
4+
now accepted and sent quoted.

0 commit comments

Comments
 (0)