T09 · Insecure Skill Coding Practices
- Location
scripts/send_email.py:52- Finding
SMTP Certificate Verification Is Disabled and Plaintext Authentication Is Permitted
- Content
View full analysis
Vulnerability Details
File Location:
scripts/send_email.py, lines 52–98
Vulnerability Type: Improper TLS certificate validation and permitted plaintext SMTP authentication
Risk Level: HighVulnerable Code
python smtp_host = conf.get("SMTP_HOST", "127.0.0.1") smtp_port = int(conf.get("SMTP_PORT", "1025")) smtp_user = conf.get("PROTON_BRIDGE_USER") or conf.get("PROTON_EMAIL") smtp_pass = conf.get("PROTON_BRIDGE_PASS") sec = (conf.get("SMTP_SECURITY") or "").upper()python # Proton Bridge uses a local cert; for localhost automation we allow it. local_ctx = ssl._create_unverified_context() if "SSL" in sec and "START" not in sec: with smtplib.SMTP_SSL(smtp_host, smtp_port, context=local_ctx, timeout=30) as s: if smtp_user and smtp_pass: s.login(smtp_user, smtp_pass) s.send_message(msg) elif "START" in sec: with smtplib.SMTP(smtp_host, smtp_port, timeout=30) as s: s.ehlo() s.starttls(context=local_ctx) s.ehlo() if smtp_user and smtp_pass: s.login(smtp_user, smtp_pass) s.send_message(msg) else: with smtplib.SMTP(smtp_host, smtp_port, timeout=30) as s: s.ehlo() if smtp_user and smtp_pass: s.login(smtp_user, smtp_pass) s.send_message(msg)Technical Analysis
The SMTP host and security mode are loaded from the encrypted configuration without enforcing the documented localhost-only trust boundary. TLS connections use
ssl._create_unverified_context(), which disables certificate-chain and hostname validation. Consequently, encryption may be established with an attacker-controlled endpoint without authenticating that endpoint.The final branch also permits SMTP authentication when TLS is not enabled. If
SMTP_SECURITYis empty, unrecognized, or explicitly configured asNONE,s.login()can transmit the Bridge username and pass ...[truncated 2127 chars]- Remediation
View remediation
Remediation Suggestions
- Enforce the intended local-only boundary by accepting only literal loopback addresses or hostnames that resolve exclusively to loopback addresses. Reject all other destinations unless an explicit secure remote mode is implemented.
- Replace
ssl._create_unverified_context()withssl.create_default_context()for authenticated TLS. - If Proton Bridge requires a self-signed certificate, trust a dedicated local CA or pin the expected Bridge certificate or public key instead of disabling verification globally.
- Reject unknown
SMTP_SECURITYvalues. Use an explicit allowlist such asSTARTTLSandSSL. - Prohibit
SMTP_SECURITY=NONEwhenever credentials or sensitive message content are transmitted. If plaintext SMTP must remain available for a narrowly defined loopback deployment, require an explicit opt-in and verify that the destination is loopback. - Validate all required configuration values before opening a connection and fail closed when the security mode is absent or malformed.
- Document certificate enrollment or pin rotation procedures so certificate verification is not disabled as an operational workaround.
