diff --git a/Lib/imaplib.py b/Lib/imaplib.py index 977d6bdb1c3d86b..10a5fda517c5cb2 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -908,12 +908,14 @@ def login_plain(self, user, password): user = user.encode('utf-8') if isinstance(password, str): password = password.encode('utf-8') + user = bytes(user) + password = bytes(password) if b'\0' in user or b'\0' in password: raise ValueError("NUL is not allowed in user name or password") # An empty authorization identity (RFC 4616) makes the server # derive it from the authentication identity; a non-empty one # requests proxy authorization and is often rejected. - response = b'\0' + bytes(user) + b'\0' + bytes(password) + response = b'\0' + user + b'\0' + password return self.authenticate("PLAIN", lambda _: response) diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py index da63da54e8ef733..86e7d73a17b3217 100644 --- a/Lib/test/test_imaplib.py +++ b/Lib/test/test_imaplib.py @@ -851,6 +851,10 @@ def test_login_plain_nul(self): client.login_plain('user\0', 'pass') with self.assertRaises(ValueError): client.login_plain('user', b'pa\0ss') + with self.assertRaises(ValueError): + client.login_plain(memoryview(b'user\0'), 'pass') + with self.assertRaises(ValueError): + client.login_plain('user', memoryview(b'pa\0ss')) def test_aborted_authentication(self): class MyServer(SimpleIMAPHandler): diff --git a/Misc/NEWS.d/next/Library/2026-10-17-20-29-17.gh-issue-159631.Vkc3k7.rst b/Misc/NEWS.d/next/Library/2026-10-17-20-29-17.gh-issue-159631.Vkc3k7.rst new file mode 100644 index 000000000000000..8830afcf19346f0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-10-17-20-29-17.gh-issue-159631.Vkc3k7.rst @@ -0,0 +1,2 @@ +:meth:`imaplib.IMAP4.login_plain` now rejects NUL in a user name or password +given as a :class:`memoryview` or another :term:`bytes-like object`.