
Scoperta di CVE-2025-22381: Host Header Injection nel progetto open-source Aggie
Analisi dettagliata e Proof-of-Concept per CVE-2025-22381, una vulnerabilità di Iniezione dell'header Host scoperta nel progetto open-source Aggie.
Panoramica della vulnerabilità+
CVE ID: CVE-2025-22381
Pubblicata: ottobre 2025 (assegnazione MITRE)
Divulgata pubblicamente: febbraio 2026
Segnalatore: Anas Abderrahman Benbarek
Data della scoperta: 17 settembre 2025
Progetto interessato: TID-Lab/aggie
Versioni interessate: tutte le versioni (incluse 2.6.1 e precedenti; nessuna correzione applicata a febbraio 2026)
Gravità: da media ad alta (CVSS stimato ~7.1–7.5)
Impatto: consente attacchi di phishing che portano al furto del token di reimpostazione della password e a una potenziale compromissione dell'account.
Contesto
Dedico parecchio tempo a rivedere progetti open source node.js su GitHub, in particolare quelli che gestiscono i flussi di autenticazione. Nel settembre 2025, mentre esaminavo il repository di Aggie, ho notato qualcosa che spiccava immediatamente nella logica di reimpostazione della password. Quella che era iniziata come una normale lettura del codice è diventata CVE-2025-22381 — una classica vulnerabilità di Iniezione dell'header Host che consente a un attaccante di controllare il dominio nelle email di reimpostazione della password.
Come l'ho scoperta
Ho clonato il repository e ho iniziato a leggere i file in lib/api/, concentrandomi su tutto ciò che riguarda l'autenticazione e la generazione di email.
Il file lib/api/reset-password.js contiene la logica dell'endpoint per /reset-password. La parte critica è all'interno dell'helper sendEmail:
function sendEmail(user, req, callback) {
var token = encodeToken(user);
mailer.sendFromTemplate({
template: 'forgotPassword',
user: user,
token: token,
host: req.headers.host, // ← vulnerable
protocol: req.protocol,
acceptLanguage: req.headers['accept-language']
}, callback);
}
Il problema è la riga host: req.headers.host. In express, req.headers.host proviene direttamente dall'header HTTP Host, che è interamente controllato dall'attaccante. Non c'è validazione, nessuna whitelist, nessun fallback a un dominio attendibile proveniente dalla configurazione.
Conferma iniziale
Ho configurato rapidamente un'istanza locale seguendo le istruzioni del README (Ubuntu, nvm, npm install, secrets.json con SMTP di test), ho avviato il server e ho attivato una reimpostazione della password. Come previsto, il link nell'email generata usava localhost:3000.
Poi ho ripetuto la richiesta con un header Host manipolato:
curl -X POST http://localhost:3000/reset-password \
-H "Host: evil-phish.example" \
-d "[email protected]"
L'email (catturata tramite MailHog) conteneva: http://evil-phish.example/reset-password?token=...
Prova lampante. L'applicazione si fida dell'header Host fornito dal client quando costruisce il link di reimpostazione.
Come funziona realmente l'attacco
L'attaccante invia una richiesta di reimpostazione della password per l'indirizzo email della vittima, ma imposta l'header Host su un dominio che controlla (es. evil-phish.example).
Aggie genera un token di reimpostazione legittimo (lato server, con scadenza temporale, crittografato con il segreto di configurazione).
L'email viene inviata con un link al dominio dell'attaccante invece che a quello reale.
La vittima riceve l'email e fa clic sul link (condizione di successo del phishing).
La vittima finisce sul server dell'attaccante.
Il server dell'attaccante può:
Semplicemente mostrare una pagina falsa di “reimpostazione non riuscita” e scartare silenziosamente il token, oppure
Catturare il token dalla query string (tramite logging lato server o JavaScript), oppure
Fare da proxy alla richiesta verso l'istanza reale di Aggie, catturare il token e inoltrare l'utente alla pagina di reimpostazione legittima (così la vittima non nota subito nulla di anomalo).
In seguito, l'attaccante usa il token catturato sul dominio reale per reimpostare la password della vittima.
Il punto chiave: l'iniezione dell'header Host da sola non consente all'attaccante di usare direttamente il token. L'attaccante ha comunque bisogno che la vittima visiti il link malevolo affinché il token raggiunga l'infrastruttura dell'attaccante. Ecco perché questa è una vulnerabilità che abilita il phishing piuttosto che una compromissione diretta dell'account senza interazione dell'utente.
Gravità tecnica e impatto
Questo è un problema di gravità medio-alta a seconda del contesto:
AV:N: Raggiungibile dalla rete
PR:N: Nessun privilegio richiesto
AC:L: Bassa complessità
UI:R: Richiede interazione dell'utente
S:C: L'ambito può cambiare (l'impatto si estende all'account della vittima sul dominio legittimo)
C:L / I:H: Impatto su riservatezza e integrità dell'account della vittima
Molti database lo classificano in un intervallo CVSS di ~7.1–7.5. Personalmente lo considero serio in ambienti di produzione in cui Aggie viene utilizzato per monitoraggi sensibili (elezioni, crisi), poiché un phishing riuscito qui può portare alla completa compromissione dell'account.
Proof-of-Concept (dettagliato e riproducibile)
Ambiente
Ubuntu 18.04/20.04 (come consigliato)
Node 12.16 (secondo .nvmrc)
MailHog: in esecuzione locale per la cattura delle email (docker run -d -p 8025:8025 -p 1025:1025 mailhog/mailhog)
Aggie configurato con email.transport che punta a localhost:1025
Passo dopo passo
Clona e avvia Aggie:
git clone https://github.com/TID-Lab/aggie.git cd aggie nvm install npm install cp config/secrets.json.example config/secrets.json edit secrets.json → set adminPassword, add test SMTP if needed npm start
Crea un utente di test tramite l'interfaccia web o direttamente in MongoDB.
Attiva la reimpostazione malevola:
curl -i -X POST http://localhost:3000/reset-password
-H "Host: evil-phish.example"
-H "Content-Type: application/x-www-form-urlencoded"
-d "email=[email protected]"
Apri MailHog: ispeziona l'email inviata. Il link di reimpostazione punterà a http://evil-phish.example/reset-password?token=...
Cronologia della divulgazione
17 set 2025: Scoperta + PoC locale
17 set 2025: Inviata un'email a [email protected] con tutti i dettagli e il PoC
17 set 2025: Inviata a MITRE (service request 1926730 / MCID15453119)
9 ott 2025: MITRE ha assegnato CVE-2025-22381
Ott–dic 2025: Nessuna patch pubblica o risposta osservata
Feb 2026: Divulgazione pubblica (questo articolo)
Correzione consigliata
Modifica del codice
Sostituisci la riga vulnerabile con un valore attendibile in lib/api/reset-password.js:
// In lib/api/reset-password.js, inside sendEmail() const config = require('../../config/secrets').get();
// Option A: Hard trust config value (recommended for single-domain) const host = config.appHost || 'localhost:3000';
// Then use it: mailer.sendFromTemplate({ template: 'forgotPassword', user: user, token: token, host: host, // Use the trusted variable protocol: config.environment === 'production' ? 'https' : req.protocol, acceptLanguage: req.headers['accept-language'] }, callback);
Configurazione
Aggiungi a secrets.json:
"appHost": "https://your-real-domain.com"
Considerazioni finali
L'iniezione dell'header Host rimane sorprendentemente comune nel 2025–2026, soprattutto in progetti avviati anni fa e non sottoposti a revisioni approfondite. Aggie è uno strumento prezioso per la civic tech e il monitoraggio delle crisi — spero che i manutentori applichino presto una correzione.
Se mantieni o usi Aggie, controlla la tua implementazione e applica la patch manualmente finché non verrà rilasciata una versione ufficiale. Sentiti libero di contattarmi se hai domande o vuoi discutere problemi simili in altri progetti.
Grazie per aver letto e rimani al sicuro là fuori.