Skip to content

Commit d0921ef

Browse files
gh-143921: Narrow the control character check in imaplib commands (GH-153067)
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 74a2438 commit d0921ef

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
@@ -1751,10 +1751,20 @@ def test_uppercase_command_names(self):
17511751
client.NONEXISTENT
17521752

17531753
def test_control_characters(self):
1754-
client, _ = self._setup(SimpleIMAPHandler)
1755-
for c0 in support.control_characters_c0():
1754+
client, server = self._setup(SimpleIMAPHandler)
1755+
client.login('user', 'pass')
1756+
for c in '\0\r\n':
17561757
with self.assertRaises(ValueError):
1757-
client.login(f'user{c0}', 'pass')
1758+
client.select(f'a{c}b')
1759+
# Other control characters are valid in a quoted string and can
1760+
# occur in mailbox names returned by the server, so the client
1761+
# must be able to send them back.
1762+
for c in support.control_characters_c0():
1763+
if c in '\0\r\n':
1764+
continue
1765+
typ, _ = client.select(f'a{c}b')
1766+
self.assertEqual(typ, 'OK')
1767+
self.assertEqual(server.is_selected, [f'"a{c}b"'])
17581768

17591769
# property tests
17601770

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)