
SSRF via smtplib raw TCP sockets bypassing HTTP blocklist in AutoGPT SendEmailBlock
CVE-2026-33234 | Moderado 5.0 | GHSA-4jwj-6mg5-wrwf Autor: Pavan Nallamothu
Eu estava mapeando cada entrada controlada pelo usuário que tocava a rede na Plataforma AutoGPT. A camada HTTP estava bem protegida. Faixas de IP privadas (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), loopback, endpoints de metadados de nuvem — tudo em lista de bloqueio. Confirmei o gateway HTTP de vários ângulos. Nada passava.
Então abri o esquema de configuração do SendEmailBlock.
O campo do servidor SMTP era uma entrada de texto livre. Não era uma credencial de administrador. Não era uma configuração bloqueada definida uma vez na implantação. Um campo que qualquer usuário autenticado poderia preencher com o que quisesse. Rastreei o caminho do código e descobri que smtplib.SMTP() abre um socket TCP bruto. Essa conexão nunca passa pelo caminho HTTP onde a lista de bloqueio de IPs reside. Existiam dois caminhos de saída na plataforma. Apenas um era protegido.
Apontei o servidor SMTP para localhost:22.
O banner SSH voltou na mensagem de erro. O smtplib conecta-se a qualquer coisa que você fornecer, tenta ler um cumprimento SMTP 220 e, quando recebe outra coisa, envolve os bytes brutos em um SMTPConnectError. Essa exceção se propaga pelo framework de execução do AutoGPT e aparece claramente na saída do bloco. Eu estava vendo a string de versão SSH do alvo sem nunca tocar na camada HTTP.
Isso é o que tornou interessante. O smtplib não é apenas um cliente de e-mail. É um coletor de banners TCP com relatórios de erro estruturados. Aponte-o para a porta 6379 e você obtém a assinatura de protocolo do Redis. Aponte-o para uma porta fechada e o ConnectionRefusedError informa que o host está ativo, mas a porta está inativa. Aponte-o para 169.254.169.254:80 e você confirma que o endpoint de metadados de nuvem está acessível. Cada tentativa de conexão retorna um erro diferente e informativo. SSRF não-cego através de um recurso que deveria enviar e-mail.
O design do SMTPConfig agrava o problema. Em uma arquitetura segura, o endereço do servidor SMTP seria uma credencial controlada pelo administrador — definida uma vez, bloqueada, nunca exposta aos usuários. Em vez disso, é uma entrada por execução. Cada usuário autenticado controla onde a plataforma abre conexões TCP.
# Configuração do SendEmailBlock - defina o servidor SMTP para alvos internos
# Escanear SSH
smtp_server = "10.0.0.5"
smtp_port = 22
# O erro revela: "SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.6"
# Escanear Redis
smtp_server = "10.0.0.5"
smtp_port = 6379
# O erro revela: "-ERR unknown command ..."
# Escanear porta fechada
smtp_server = "10.0.0.5"
smtp_port = 9999
# O erro revela: "ConnectionRefusedError" (porta fechada, host ativo)
# Acessar metadados de nuvem
smtp_server = "169.254.169.254"
smtp_port = 80
# Confirma a acessibilidade do endpoint de metadados
Verifiquei toda a cadeia através da API de execução de blocos:
# Teste direto equivalente contra a API de execução de blocos
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"
}
}'
# A resposta contém SMTPConnectError com o banner SSH
graph LR
A[Atacante define o servidor SMTP para IP interno] --> B[SendEmailBlock chama smtplib.SMTP]
B --> C[Conexão TCP bruta para alvo:porta]
C --> D{O serviço responde?}
D -->|Sim| E[Banner lido como cumprimento SMTP]
E --> F[SMTPConnectError com dados do banner]
F --> G[O erro se propaga para a saída do bloco]
D -->|Não| H[ConnectionRefused = porta fechada]
G --> I[Atacante lê a versão do serviço]A superfície de ataque que isso abre é significativa. Banners SSH revelam versões exatas (OpenSSH_8.9p1 Ubuntu-3ubuntu0.6). O Redis vaza sua assinatura de protocolo. O MySQL envia sua string de versão. Cada banner é uma consulta de CVE esperando para acontecer. Um atacante mapeia a rede interna, identifica cada serviço em execução e sua versão exata, e então ataca o mais fraco. Tudo a partir de um campo de texto rotulado como "Servidor SMTP."
Três verificações ausentes criaram isso: nenhuma validação de IP no caminho SMTP, nenhuma restrição de porta, nenhuma sanitização de exceções. A plataforma protegeu todas as portas de saída, exceto a rotulada como "correio de saída."
Relatei o problema à Significant Gravitas. Eles entenderam a lacuna arquitetural imediatamente.
Corrigido em: autogpt-platform-backend 0.6.52 (validação do servidor SMTP adicionada à aplicação da lista de bloqueio, restrições de porta aplicadas)