
SSRF via smtplib raw TCP sockets bypassing HTTP blocklist in AutoGPT SendEmailBlock
CVE-2026-33234 | Moderate 5.0 | GHSA-4jwj-6mg5-wrwf Author: Pavan Nallamothu
I was mapping every user-controlled input that touched the network in AutoGPT Platform. The HTTP layer was locked down tight. Private IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), loopback, cloud metadata endpoints -- all blocklisted. I confirmed the HTTP gate from multiple angles. Nothing got through.
Then I opened the SendEmailBlock config schema.
The SMTP server field was a free-text input. Not an admin credential. Not a locked-down configuration set once at deployment. A field any authenticated user could fill in with whatever they wanted. I traced the code path and found that smtplib.SMTP() opens a raw TCP socket. That connection never passes through the HTTP path where the IP blocklist lives. Two outbound paths existed in the platform. Only one was protected.
I pointed the SMTP server at localhost:22.
The SSH banner came back in the error message. smtplib connects to whatever you give it, tries to read an SMTP 220 greeting, and when it gets something else, wraps the raw bytes in an SMTPConnectError. That exception propagates through AutoGPT's execution framework and surfaces cleanly in the block output. I was looking at the target's SSH version string without ever touching the HTTP layer.
This is what made it interesting. smtplib is not just an email client. It is a TCP banner grabber with structured error reporting. Point it at port 6379 and you get Redis's protocol signature. Point it at a closed port and ConnectionRefusedError tells you the host is alive but the port is down. Point it at 169.254.169.254:80 and you confirm the cloud metadata endpoint is reachable. Each connection attempt returns a different, informative error. Non-blind SSRF through a feature that was supposed to send email.
The SMTPConfig design compounds the problem. In a secure architecture, the SMTP server address would be an admin-controlled credential -- set once, locked, never exposed to users. Instead, it is a per-execution input. Every authenticated user controls where the platform opens TCP connections.
# SendEmailBlock configuration - set SMTP server to internal targets
# Scan SSH
smtp_server = "10.0.0.5"
smtp_port = 22
# Error reveals: "SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6"
# Scan Redis
smtp_server = "10.0.0.5"
smtp_port = 6379
# Error reveals: "-ERR unknown command ..."
# Scan closed port
smtp_server = "10.0.0.5"
smtp_port = 9999
# Error reveals: "ConnectionRefusedError" (port closed, host alive)
# Hit cloud metadata
smtp_server = "169.254.169.254"
smtp_port = 80
# Confirms metadata endpoint reachability
I verified the full chain through the block execution API:
# Equivalent direct test against the block execution API
curl -X POST https://autogpt-platform/api/blocks/execute \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"block_id": "send_email_block",
"inputs": {
"smtp_server": "10.0.0.5",
"smtp_port": 22,
"to": "[email protected]",
"subject": "test",
"body": "test"
}
}'
# Response contains SMTPConnectError with SSH banner
graph LR
A[Attacker sets SMTP server to internal IP] --> B[SendEmailBlock calls smtplib.SMTP]
B --> C[Raw TCP connect to target:port]
C --> D{Service responds?}
D -->|Yes| E[Banner read as SMTP greeting]
E --> F[SMTPConnectError with banner data]
F --> G[Error propagates to block output]
D -->|No| H[ConnectionRefused = port closed]
G --> I[Attacker reads service version]The attack surface this opens is significant. SSH banners reveal exact versions (OpenSSH_8.9p1 Ubuntu-3ubuntu0.6). Redis leaks its protocol signature. MySQL sends its version string. Each banner is a CVE lookup waiting to happen. An attacker maps the internal network, identifies every running service and its exact version, then targets the weakest one. All from a text field labeled "SMTP Server."
Three missing checks created this: no IP validation on the SMTP path, no port restriction, no exception sanitization. The platform protected every outbound door except the one labeled "outgoing mail."
I reported the issue to Significant Gravitas. They understood the architectural gap immediately.
Fixed in: autogpt-platform-backend 0.6.52 (SMTP server validation added to blocklist enforcement, port restrictions applied)