
Vulnerabilità di Esecuzione Remota di Codice tramite Iniezione AST in Handlebars.js
Questo post è un articolo di ricerca pubblicato da EQSTLab.
PoC di riferimento: dinhvaren/cve-2026-33937
★ CVE-2026-33937 PoC di Remote Code Execution tramite AST Injection in Handlebars.js ★
https://github.com/user-attachments/assets/99e383e7-e71f-4e10-8c62-f50abff8b4f5
CVE-2026-33937 : Vulnerabilità di Remote Code Execution tramite AST Injection in Handlebars.js
| Versioni interessate | 4.0.0 – 4.7.8 |
| Versione con patch | 4.7.9 |
| Punteggio CVSS | 9.8 (Critico) |
Una vulnerabilità di Type Confusion in Handlebars.js deriva dal fatto che Handlebars.compile() accetta come input non solo una stringa di template ma anche un oggetto AST pre-analizzato (JSON). Un attaccante che controlla il valore passato a compile() può fornire un oggetto AST appositamente costruito in cui il campo value di un nodo NumberLiteral viene sostituito con una stringa JavaScript arbitraria. Poiché il generatore di codice interno inserisce tale campo direttamente nel corpo della funzione JavaScript emessa senza sanificazione, la funzione risultante esegue codice controllato dall'attaccante al momento del rendering, ottenendo l'esecuzione di codice remota sul server.
Costruisci ed esegui l'ambiente vulnerabile usando Docker:
Costruzione dell'immagine
docker build -t cve-2026-33937-server .
Esegui il container
docker run --name cve-2026-33937 -p 12701:12701 -p 9229:9229 cve-2026-33937-server
Oppure usa gli script npm forniti:
npm run docker:up # build + run in one step
L'applicazione è servita su http://localhost:12701.
Interfaccia Web
Apri http://localhost:12701 in un browser. La pagina presenta un'interfaccia di creazione di email B2B. I valori dei campi forniti dall'utente vengono interpolati in una stringa di template Handlebars lato client e poi inviati al server per il rendering. Inietta un payload Handlebars dannoso tramite i campi di input o direttamente tramite l'API.
API diretta
# POST crafted template to the vulnerable endpoint
curl -s -X POST http://localhost:12701/api/email/preview \
-H "Content-Type: application/json" \
-d '{"subject":"test","editorTemplateData":"<PAYLOAD>"}'
Sostituisci <PAYLOAD> con un payload di AST injection che ha come target Handlebars.compile().
POST /api/email/preview
Il server accetta un corpo JSON contenente editorTemplateData e lo passa direttamente a Handlebars.compile() senza sanificazione o applicazione di una allowlist:
// app.js
const renderEmail = Handlebars.compile(editorTemplateData);
Handlebars.compile() è documentato per accettare una stringa di template, ma il suo controllo di tipo interno consente anche di passare direttamente un oggetto AST pre-analizzato. All'interno di javascript-compiler.js, il visitor NumberLiteral() emette il campo value del nodo così com'è nel sorgente JavaScript generato, senza alcuna validazione di tipo o sanificazione:
// javascript-compiler.js (simplified)
NumberLiteral(number) {
this.pushStackLiteral(number.value); // value inserted as-is into emitted JS
}
Se un attaccante fornisce un oggetto AST appositamente costruito in cui number.value è una stringa contenente JavaScript arbitrario (ad es. "1; require('child_process').execSync(...)") invece di un letterale numerico, il corpo della funzione emessa contiene ed esegue quel codice al momento del rendering.
Il pattern pericoloso nell'applicazione vulnerabile è:
const render = Handlebars.compile(userInput); // userInput may be a crafted AST object
render(safeContextData); // attacker code runs here
Nota sulla tecnica di sfruttamento: I PoC pubblici esistenti (incluso quello citato) ottengono l'iniezione tramite un nodo
NumberLiteralcombinato con un helperlookup. Questo PoC conferma la stessa primitiva RCE utilizzando un nodoBooleanLiteralcombinato con l'helper integratolog, dimostrando che la type confusion non è limitata a un singolo tipo di nodo o funzione helper.
/api/email/preview con un valore editorTemplateData appositamente costruito.Handlebars.compile() sull'oggetto AST controllato dall'attaccante.render() innesca l'esecuzione di JavaScript arbitrario nel processo del server.Quando Handlebars è implementato in un ambiente backend Node.js, questa vulnerabilità porta a un percorso di esecuzione del codice lato server, a differenza dei normali XSS lato client. L'attacco non richiede che alcun output venga riflesso all'utente; il payload viene eseguito all'interno del processo Node.js con gli stessi privilegi dell'applicazione. A seconda del deployment:
/etc/passwd) possono essere letti ed esfiltrati.+-------------------------------------------+
| Attacker |
+-------------------------------------------+
|
| POST /api/email/preview
| {"editorTemplateData": "<malicious payload>"}
v
+-------------------------------------------+
| Handlebars.compile(editorTemplateData) |
| (No sanitization — app.js:17) |
+-------------------------------------------+
|
| AST node injection
| breaks template sandbox
v
+-------------------------------------------+
| Arbitrary JS Execution (Server Process) |
+-------------------------------------------+
|
| Read sensitive files, spawn shell,
| exfiltrate secrets, etc.
v
+-------------------------------------------+
| Remote Code Execution (RCE) |
+-------------------------------------------+
Aggiorna Handlebars.js a 4.7.9 o versioni successive.
La versione 4.7.9 introduce una validazione rigorosa del tipo di input in compile(), rifiutando argomenti non stringa prima dell'inizio della generazione del codice.
Applica un controllo di tipo prima di chiamare compile().
Se un aggiornamento immediato non è possibile, verifica che l'argomento sia sempre una string nel punto di chiamata:
if (typeof templateInput !== 'string') throw new TypeError('Template must be a string');
const render = Handlebars.compile(templateInput);
Usa handlebars/runtime per la pre-compilazione in fase di build.
Pre-compila i template in fase di build con la CLI di Handlebars e distribuisci solo il bundle runtime. La build runtime non include compile(), eliminando completamente la superficie d'attacco per i deployment in produzione.
Questo repository è destinato esclusivamente alla ricerca sulla sicurezza, all'istruzione e alla dimostrazione controllata di vulnerabilità. Non deve essere utilizzato per testare o sfruttare sistemi senza un'autorizzazione esplicita e scritta del proprietario del sistema. Lo scopo di questo progetto è aiutare ricercatori di sicurezza, difensori e sviluppatori a comprendere la vulnerabilità, validare l'esposizione in ambienti di laboratorio controllati e applicare mitigazioni efficaci.