
Descoberta do CVE-2025-22381: Injeção de Cabeçalho de Host no Projeto Open-Source Aggie
CVE-2025-22381: Injeção de Cabeçalho de Host no Aggie
Análise detalhada e Prova-de-Conceito para CVE-2025-22381, uma vulnerabilidade de Injeção de Cabeçalho de Host descoberta no Projeto Open-Source Aggie.
Visão Geral da Vulnerabilidade+
CVE ID: CVE-2025-22381
Publicado: Outubro de 2025 (atribuição MITRE)
Divulgado publicamente: Fevereiro de 2026
Relator: Anas Abderrahman Benbarek
Data da Descoberta: 17 de Setembro de 2025
Projeto Afetado: TID-Lab/aggie
Versões Afetadas: Todas as versões (incluindo 2.6.1 e anteriores; nenhuma correção aplicada até Fevereiro de 2026)
Gravidade: Média a Alta (CVSS estimado ~7,1–7,5)
Impacto: Possibilita ataques de phishing que levam ao roubo de tokens de redefinição de senha e potencial tomada de conta.
Contexto
Passo uma quantidade razoável de tempo revisando projetos node.js de código aberto no GitHub, especialmente aqueles que lidam com fluxos de autenticação. Em Setembro de 2025, enquanto examinava o repositório Aggie, notei algo que imediatamente se destacou na lógica de redefinição de senha. O que começou como uma leitura rotineira de código acabou se tornando CVE-2025-22381 — uma vulnerabilidade clássica de Injeção de Cabeçalho de Host que permite a um atacante controlar o domínio nos emails de redefinição de senha.
Como Encontrei
Clonei o repositório e comecei a ler os arquivos em lib/api/, focando em qualquer coisa relacionada a autenticação e geração de emails.
O arquivo lib/api/reset-password.js contém a lógica do endpoint para /reset-password. A parte crítica está dentro do helper sendEmail:
function sendEmail(user, req, callback) { var token = encodeToken(user);
mailer.sendFromTemplate({ template: 'forgotPassword', user: user, token: token, host: req.headers.host, // ← vulnerável protocol: req.protocol, acceptLanguage: req.headers['accept-language'] }, callback); }
A linha host: req.headers.host é o problema. No Express, req.headers.host vem diretamente do cabeçalho HTTP Host, que é totalmente controlado pelo atacante. Não há validação, lista branca ou fallback para um domínio confiável da configuração.
Confirmação Inicial
Rapidamente configurei uma instância local seguindo as instruções do README (Ubuntu, nvm, npm install, secrets.json com SMTP de teste), iniciei o servidor e acionei uma redefinição de senha. O link do email gerado usava localhost:3000 como esperado.
Em seguida, repeti a requisição com um cabeçalho Host manipulado:
curl -X POST http://localhost:3000/reset-password
-H "Host: evil-phish.example"
-d "email=[email protected]"
O email (capturado via MailHog) continha: http://evil-phish.example/reset-password?token=...
Prova positiva. A aplicação confia no cabeçalho Host fornecido pelo cliente ao construir o link de redefinição.
Como o Ataque Realmente Funciona
O atacante envia uma solicitação de redefinição de senha para o endereço de email da vítima, mas define o cabeçalho Host para um domínio que controla (por exemplo, evil-phish.example).
O Aggie gera um token de redefinição legítimo (no lado do servidor, com limite de tempo, criptografado com o segredo da configuração).
O email é enviado contendo um link para o domínio do atacante em vez do real.
A vítima recebe o email e clica no link (condição de sucesso do phishing).
A vítima acessa o servidor do atacante.
O servidor do atacante pode:
Simplesmente exibir uma página falsa de "redefinição falhou" e descartar silenciosamente o token, ou
Capturar o token da string de consulta (através de logs do servidor ou JavaScript), ou
Fazer proxy da requisição para a instância real do Aggie, capturar o token e encaminhar o usuário para a página legítima de redefinição (para que a vítima não perceba nada de errado imediatamente).
Mais tarde, o atacante usa o token capturado no domínio real para redefinir a senha da vítima.
O ponto chave: a injeção de cabeçalho Host sozinha não permite que o atacante use o token diretamente. O atacante ainda precisa que a vítima visite o link malicioso para que o token chegue à infraestrutura do atacante. É por isso que esta é uma vulnerabilidade que possibilita phishing, e não uma tomada de conta direta sem interação do usuário.
Gravidade Técnica e Impacto
Esta é uma questão de gravidade média a alta, dependendo do contexto:
AV:N: Acessível pela rede
PR:N: Nenhum privilégio necessário
AC:L: Baixa complexidade
UI:R: Requer interação do usuário
S:C: O escopo pode mudar (o impacto se estende à conta da vítima no domínio legítimo)
C:L / I:H: Impacto na confidencialidade e integridade da conta da vítima
Muitas bases de dados listam com CVSS na faixa ~7,1–7,5. Pessoalmente, considero grave em ambientes de produção onde o Aggie é usado para monitoramento sensível (eleições, crises), pois um phishing bem-sucedido aqui pode levar à tomada total da conta.
Prova-de-Conceito (Detalhada e Reproduzível)
Ambiente
docker run -d -p 8025:8025 -p 1025:1025 mailhog/mailhog)email.transport apontando para localhost:1025Passo a passo
git clone https://github.com/TID-Lab/aggie.git
cd aggie
nvm install
npm install
cp config/secrets.json.example config/secrets.json
# editar secrets.json → definir adminPassword, adicionar SMTP de teste se necessário
npm start
Crie um usuário de teste via interface web ou diretamente no MongoDB.
Acione a redefinição maliciosa:
curl -i -X POST http://localhost:3000/reset-password \
-H "Host: evil-phish.example" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "[email protected]"
http://evil-phish.example/reset-password?token=...Linha do Tempo da Divulgação
Correção Recomendada
Alteração de Código
Substitua a linha vulnerável por um valor confiável em lib/api/reset-password.js:
// Em lib/api/reset-password.js, dentro de sendEmail()
const config = require('../../config/secrets').get();
// Opção A: Valor de configuração de confiança (recomendado para domínio único)
const host = config.appHost || 'localhost:3000';
// Então use-o:
mailer.sendFromTemplate({
template: 'forgotPassword',
user: user,
token: token,
host: host, // Use a variável confiável
protocol: config.environment === 'production' ? 'https' : req.protocol,
acceptLanguage: req.headers['accept-language']
}, callback);
Configuração
Adicione ao secrets.json:
"appHost": "https://seu-dominio-real.com"
Considerações Finais
A injeção de cabeçalho Host continua surpreendentemente comum em 2025–2026, especialmente em projetos que foram iniciados há anos e não passaram por auditoria pesada. O Aggie é uma ferramenta valiosa para tecnologia cívica e monitoramento de crises — espero que os mantenedores apliquem uma correção em breve.
Se você mantém ou usa o Aggie, verifique sua implantação e aplique o patch manualmente até que uma versão oficial seja lançada. Fique à vontade para entrar em contato se tiver dúvidas ou quiser discutir problemas semelhantes em outros projetos.
Obrigado por ler e fique seguro por aí.