Skip to content

smtplib — unverified context

Improper Certificate Validation Using smtplib

The Python class smtplib.SMTP_SSL by default creates an SSL context that does not verify the server's certificate if the context parameter is unset or has a value of None. This means that an attacker can easily impersonate a legitimate server and fool your application into connecting to it.

If you use smtplib.SMTP_SSL or starttls without a context set, you are opening your application up to a number of security risks, including:

  • Machine-in-the-middle attacks
  • Session hijacking
  • Data theft

Example

smtplib_smtp_ssl_context_unset.py
import smtplib


def prompt(prompt):
    return input(prompt).strip()


fromaddr = prompt("From: ")
toaddrs = prompt("To: ").split()
print("Enter message, end with ^D (Unix) or ^Z (Windows):")

# Add the From: and To: headers at the start!
msg = "From: {}\r\nTo: {}\r\n\r\n".format(fromaddr, ", ".join(toaddrs))
while True:
    try:
        line = input()
    except EOFError:
        break
    if not line:
        break
    msg = msg + line

print("Message length is", len(msg))

server = smtplib.SMTP_SSL("localhost")
server.login("user", "password")
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()
Example Output
> precli tests/unit/rules/python/stdlib/smtplib/examples/smtplib_smtp_ssl_context_unset.py
⚠️  Warning on line 25 in tests/unit/rules/python/stdlib/smtplib/examples/smtplib_smtp_ssl_context_unset.py
PY026: Improper Certificate Validation
The 'smtplib.SMTP_SSL' function does not properly validate certificates when context is unset or None.

Remediation

Set the value of the context keyword argument to ssl.create_default_context() to ensure the connection is fully verified.

smtplib_smtp_ssl_context_unset.py
import smtplib
import ssl


def prompt(prompt):
    return input(prompt).strip()


fromaddr = prompt("From: ")
toaddrs = prompt("To: ").split()
print("Enter message, end with ^D (Unix) or ^Z (Windows):")

# Add the From: and To: headers at the start!
msg = "From: {}\r\nTo: {}\r\n\r\n".format(fromaddr, ", ".join(toaddrs))
while True:
    try:
        line = input()
    except EOFError:
        break
    if not line:
        break
    msg = msg + line

print("Message length is", len(msg))

server = smtplib.SMTP_SSL(
    "localhost",
    context=ssl.create_default_context(),
)
server.login("user", "password")
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()

Default Configuration

enabled = true
level = "warning"

See also

New in version 0.3.14