Hermes parou de acreditar no dmarc=pass do próprio remetente

Você colocou o Hermes na sua caixa de entrada: o resumo diário chega, ele lê, resume e lembra. Depois de uma atualização, nada mais chega — nem mesmo de remetentes na sua allowlist. A única pista é uma linha WARNING no log, citando uma configuração que você nunca definiu.
O problema é a pergunta “quem de fato enviou isto?”. O Hermes verifica o header Authentication-Results para estabelecer a identidade do remetente, e esse header é texto simples que o próprio remetente pode escrever. Quando o seu servidor de recebimento não carimba a própria versão, uma linha injetada fica por cima e o Hermes costumava tratá-la como autoritativa. A correção é direta: sem pin, sem confiança.
Como a falsificação funcionava
Authentication-Results é o header que atesta “esta mensagem passou por SPF / DKIM / DMARC”. Normalmente o seu servidor de recebimento o adiciona depois que a mensagem chega — justamente porque o servidor fez a verificação, o veredito dele é o que vale a pena ler.
Mas é um header normal. Um remetente pode incluir a própria linha: attacker.self; dmarc=pass header.from=allowed.example. Se você roda um MTA auto-hospedado que não carimba um authserv-id próprio (estilo OpenDKIM / OpenDMARC), essa linha fica por cima. O comportamento antigo do Hermes lia o header do topo independentemente de quem dizia tê-lo escrito, então:
- o atacante falsifica o
From:para casar com um endereço na sua allowlist; - ele adiciona a própria linha
dmarc=pass; - o Hermes considera o remetente autenticado e entrega.
O _verify_sender_authentication reescrito aceita apenas dois resultados — ele lê o Authentication-Results do topo e exige que seu authserv-id case com o seu exatamente:
if not authserv_id: # without a pin the topmost header may be one the sender wrote
return False, _MISSING_AUTHSERV_REASON
if clauses[0].strip().lower() != authserv_id:
return False, _UNTRUSTED_AUTHSERV_REASON
Dois vizinhos também foram apertados: dois resultados dmarc em um único header agora produzem ambiguous dmarc result em vez de um palpite, e um dmarc=pass precisa ter todo header.from alinhado com o domínio do From: que o Hermes analisou.
O que de fato muda depois da atualização
Esta é uma mudança de comportamento, então o raio de alcance importa:
- Quem é afetado: implantações com autenticação de remetente ativada e sem pin definido. A autenticação de remetente está ativa por padrão, incluindo configurações de acesso aberto como
EMAIL_ALLOW_ALL_USERS/GATEWAY_ALLOW_ALL_USERS. - O que acontece: toda mensagem que precise de um
From:autenticado é descartada, inclusive remetentes na allowlist, até que o operador faça uma de duas coisas — definirEMAIL_AUTHSERV_ID(ou a chave de configuraçãoplatforms.email.authserv_id), ou optar explicitamente por sair da autenticação de remetente. - O que você vê: cada conta sem pin registra um WARNING quando se conecta, dizendo que o authserv-id não está configurado e que o Hermes se recusa a confiar em
Authentication-Results, além das duas saídas de emergência (definir o authserv-id, ou definirrequire_authenticated_sender: false/EMAIL_TRUST_FROM_HEADER=true). O aviso também dispara quando a primeira conexão de uma conta falha e o watcher de reconexão a traz depois. - Quem não é afetado: implantações com pin e implantações que já haviam optado por sair. Elas se comportam exatamente como antes.
Encontrando o valor para fixar
Não adivinhe. Abra uma mensagem que o seu servidor entregou, veja o código-fonte bruto (“Show original” no Gmail), encontre o header Authentication-Results do topo e pegue o token antes do primeiro ponto e vírgula.
- No Gmail, é
mx.google.com; - se o token muda entre mensagens, é um hostname por relay. A atitude certa então é fazer seu MTA carimbar um authserv-id estável (
AuthservIDdo OpenDKIM, o equivalente no OpenDMARC) e fixar esse.
Qualquer uma das configurações funciona; a variável de ambiente é mais amigável para contêineres:
# .env ou ambiente do contêiner
EMAIL_AUTHSERV_ID=mx.google.com
# config.yaml
platforms:
email:
authserv_id: mx.google.com
# mantenha o modo estrito padrão; só desative se você aceitar o risco de falsificação
require_authenticated_sender: true
O valor é normalizado para minúsculas, então maiúsculas/minúsculas não importam, mas o domínio precisa casar — não amplie para um domínio pai só para economizar digitação.
Se você realmente precisa que o correio flua de novo hoje
Definir platforms.email.require_authenticated_sender: false (ou EMAIL_TRUST_FROM_HEADER=true) faz o Hermes aceitar remetentes não autenticados novamente. Esse é um downgrade deliberado: em um MTA auto-hospedado, significa que qualquer um pode falsificar um remetente na allowlist. A alternativa melhor é um authserv-id estável no seu MTA — configure uma vez e pare de pensar nisso.
Para outras correções de falsificação de identidade da mesma família, veja as três correções de spoofing de identidade de remetente; o restante da configuração da plataforma de e-mail está na referência de comandos do Hermes.
Resumindo
- O
Authentication-Resultsé um header que o remetente pode escrever; em um MTA auto-hospedado sem carimbo, ele pode se ordenar no topo; - o Hermes agora exige uma correspondência exata de authserv-id e descarta mensagens que precisem de um remetente autenticado até você definir um, registrando um WARNING;
- copie o token antes do primeiro ponto e vírgula do
Authentication-Resultsdo topo (Gmail:mx.google.com) paraEMAIL_AUTHSERV_ID/platforms.email.authserv_id; - a saída é
require_authenticated_sender: falseouEMAIL_TRUST_FROM_HEADER=true, e isso significa aceitar o risco de falsificação.