Como descobrir o que está enviando spam do servidor cPanel: script PHP pelo cwd e pelo cabeçalho X-PHP, conta de e-mail invadida e como estancar o envio.
Quando um servidor começa a mandar spam, a fila do Exim incha, o IP entra em listas de bloqueio e os e-mails legítimos de todos os clientes passam a voltar. Há três origens possíveis, e cada uma pede uma correção diferente:
- Um script do site (formulário sem proteção, plugin vulnerável ou arquivo plantado por um invasor) chamando a função de e-mail do PHP.
- Uma conta de e-mail com a senha vazada, usada por robôs para enviar pelo SMTP autenticado.
- Nenhuma das duas: terceiros mandando spam de fora com o seu endereço no remetente. As devoluções chegam para você, mas nada saiu do servidor (veja e-mails devolvidos que eu não enviei).
Antes de começar
- Acesso root pelo SSH. Os comandos leem o
/var/log/exim_mainlog, que só o root acessa. - Se a fila está crescendo agora, estanque primeiro e investigue depois (seção "Como estancar o envio").
Passo 1: veja quem está enviando
Comece pela fila. Quem mais tem mensagens esperando:
exim -bpc
exim -bp | awk '/^ *[0-9]+[mhd]/{print $4}' | sort | uniq -c | sort -rn | head
Pegue o ID de uma mensagem suspeita e leia o cabeçalho com exim -Mvh ID. Três pistas resolvem a maioria dos casos:
X-Source-DireX-Source: o cPanel acrescenta esses cabeçalhos quando a opção Track email origin via X-Source email headers (em WHM » Tweak Settings, aba Mail) está ligada, que é o padrão. Mostram a pasta e o programa que gerou o e-mail.X-PHP-Originating-Script: o número do usuário e o nome do script PHP. Aparece quando a diretivamail.add_x_headerdo PHP está ligada (no cPanel, em MultiPHP INI Editor).X-Authenticated-SenderouX-Get-Message-Sender-Viacomauthenticated_id: indicam envio por SMTP autenticado, ou seja, por uma conta de e-mail, e mostram qual.
Passo 2: se for um script, encontre a pasta e o arquivo
O Exim registra a pasta de onde partiu cada envio feito por script, no campo cwd=. Conte quais pastas mais enviaram:
grep -o 'cwd=[^ ]*' /var/log/exim_mainlog | grep -v '/var/spool' | sort | uniq -c | sort -rn | head
O resultado mostra algo como:
6812 cwd=/home/usuario/public_html/wp-content/uploads/2026/09
41 cwd=/home/usuario/public_html
9 cwd=/home/outro/public_html
Uma pasta com milhares de envios, principalmente dentro de uploads, cache ou tmp, é o alvo. Liste os arquivos dela, dos mais novos para os mais antigos:
ls -lat /home/usuario/public_html/wp-content/uploads/2026/09 | head -n 20
Um PHP com nome aleatório numa pasta de imagens é quase certamente malicioso. Se a pasta for a raiz do site, o culpado pode ser um formulário de contato legítimo sendo abusado por robôs.
Passo 3: descubra quem chamou o script
O log de acesso do site mostra os IPs que acionaram o arquivo. No cPanel, os logs de cada domínio ficam em /home/usuario/access-logs/ (rode ls nessa pasta para ver os nomes; o de HTTPS termina em -ssl_log):
grep 'arquivo-suspeito.php' /home/usuario/access-logs/seudominio.com.br-ssl_log | awk '{print $1}' | sort | uniq -c | sort -rn | head
Poucos IPs com milhares de acessos via POST confirmam o abuso. A primeira chamada ao arquivo, mais antiga, ajuda a descobrir como ele foi parar ali.
Passo 4: se for uma conta de e-mail, confirme a invasão
Envio autenticado aparece no log com A=dovecot_login: ou A=dovecot_plain: seguido da conta. Quais contas mais enviaram:
grep -o 'A=dovecot_[a-z]*:[^ ]*' /var/log/exim_mainlog | sort | uniq -c | sort -rn | head
E de quais IPs uma conta suspeita está entrando:
grep 'A=dovecot_[a-z]*:[email protected]' /var/log/exim_mainlog | grep -o '\[[0-9a-f.:]*\]' | sort | uniq -c | sort -rn | head
Dezenas de IPs de países diferentes na mesma conta são a marca de uma senha vazada. Atenção à diferença: linhas com authenticator failed são tentativas recusadas e não provam invasão. O que prova é o envio autenticado com sucesso.
Como estancar o envio
- Congele as mensagens do remetente para que não saiam enquanto você investiga:
exiqgrep -i -f [email protected] | xargs -r exim -Mf - Suspenda o envio da conta cPanel sem tirar o site do ar:
Para liberar depois:whmapi1 suspend_outgoing_email user=usuariowhmapi1 unsuspend_outgoing_email user=usuario. No CloudLinux, use o caminho completo/usr/local/cpanel/bin/whmapi1. - Conta de e-mail invadida: troque a senha dela imediatamente e oriente o cliente a atualizar a senha em todos os aparelhos.
- Script malicioso: mova o arquivo para fora do
public_html(guarde como prova), procure outros com o Maldet, troque as senhas da conta e atualize o site e os plugins. - Bloqueie os IPs que acionavam o script:
csf -d 198.51.100.7 "spam via script". - Limpe a fila só depois de confirmar o que é spam:
exiqgrep -i -f [email protected] | xargs -r exim -Mrm.
Como evitar que aconteça de novo
- Limite de envio por domínio: em WHM » Tweak Settings, aba Mail, a opção Max hourly emails per domain vem ilimitada. Um limite razoável para o seu perfil de clientes contém o estrago de qualquer invasão.
- Limite por falhas: na mesma aba, Maximum percentage of failed or deferred messages a domain may send per hour bloqueia o envio de quem gera muitas devoluções, o comportamento típico de spam.
- Alerta do CSF: ligue
LF_SCRIPT_ALERTpara receber aviso quando um script passar deLF_SCRIPT_LIMITenvios (padrão 100). Exige que o Exim registre+argumentsnolog_selector. Veja alertas de e-mail do CSF. - Formulários com captcha e sites, plugins e temas sempre atualizados.
Problemas comuns
O comando do cwd não mostra nada
O Exim não está registrando os argumentos dos envios locais. Confira com exim -bP log_selector; o valor precisa incluir +arguments (ou +all). Os cabeçalhos X-Source continuam funcionando.
O IP do servidor entrou em lista de bloqueio
Resolva a origem primeiro. Depois peça a remoção no site de cada lista (Spamhaus, Barracuda, etc.); a maioria recusa o pedido enquanto o envio continuar.