
Il filtro SSRF controllava il testo dell'hostname, ma la destinazione effettiva veniva decisa successivamente dal DNS. Questo gap permetteva agli URL Webhook controllati dall'attaccante di raggiungere destinazioni di loopback, metadata e rete privata.
Il filtro SSRF controllava il testo del nome host, ma la destinazione effettiva veniva decisa successivamente dal DNS. Questa lacuna permetteva agli URL Webhook controllati dall'attaccante di raggiungere destinazioni loopback, metadata e rete privata.
Ho trovato questo problema mentre esaminavo Typebot, un costruttore di chatbot open-source, con una semplice domanda di sicurezza in mente:
Cosa succede se la protezione SSRF convalida il testo del nome host, ma la destinazione reale viene decisa successivamente dal DNS?
In questo caso, quella domanda ha portato a un bug reale.
La protezione SSRF di Typebot per i blocchi Webhook / Richiesta HTTP convalidava solo:
Non risolveva i nomi host prima di autorizzare la richiesta.
Ciò significava che un nome host come ssrf-repro.example poteva sembrare innocuo durante la convalida, per poi risolversi in:
127.0.0.1169.254.169.254ed essere comunque recuperato dal client HTTP backend.
Questo problema è diventato CVE-2026-34207.
Typebot: Typebot su GitHub
CVE: CVE-2026-34207
Corretto in: 3.16.0
Questo ha interessato Typebot, una piattaforma chatbot open-source ampiamente utilizzata. Sul suo sito ufficiale, Typebot si presenta come affidabile per oltre 650 aziende in tutto il mondo. Il sito pubblicizza anche oltre 2 milioni di chat mensili e oltre 1,5 milioni di bot pubblicati.
URL Webhook controllato dall'attaccante -> il nome host supera la convalida SSRF solo letterale -> nessuna risoluzione DNS prima della decisione di autorizzazione -> il client HTTP backend risolve il nome host in una destinazione interna -> la richiesta lato server raggiunge loopback / metadata / rete privata -> i dati della risposta diventano disponibili tramite i log di esecuzione
Typebot è un costruttore di chatbot.
Permette agli utenti di creare flussi che possono:
Webhook / Richiesta HTTPCiò significa che l'esecuzione di richieste in uscita è un vero e proprio confine di sicurezza.
La domanda importante qui non era se Typebot supportasse i blocchi Webhook.
La vera domanda era:
La protezione SSRF convalida la destinazione effettiva a cui il server si collegherà, o solo il testo del nome host che appare nell'URL?
In questo caso, convalidava solo prima la forma testuale.
Questo è stato l'errore.
Le difese SSRF falliscono in modi molto prevedibili.
La maggior parte delle volte, gli errori interessanti non sono:
169.254.169.254"localhost"Gli errori più forti sono errori di confine:
Qui era il posto giusto dove guardare.
Typebot aveva già una logica di hardening SSRF per IP metadata letterali, loopback, intervalli privati e trucchi IP codificati.
Questo rendeva ovvia la domanda successiva:
Cosa succede se il nome host non è letteralmente pericoloso, ma si risolve in una destinazione pericolosa successivamente?
Questo è esattamente ciò che è successo.
Il problema principale era la convalida della destinazione basata sul testo del nome host invece che sull'indirizzo IP risolto.
Nell'implementazione vulnerabile, validateHttpReqUrl():
http: e https:metadata.google.internal, metadata.goog, metadata e localhostQuesta è la parte importante.
Se il nome host era un valore normale come:
ssrf-repro.example
allora parseIPAddress(hostname) restituiva null, e il validatore si fermava lì.
Non avveniva alcuna risoluzione DNS prima dell'approvazione.
Quindi la logica vulnerabile si riduceva effettivamente a:
const ip = parseIPAddress(hostname);
if (ip) {
validateIPAddress(ip);
}
Ciò significa che:
La seconda metà del bug era nel percorso di esecuzione.
In executeHttpRequest(), Typebot eseguiva prima la convalida e poi successivamente effettuava la richiesta effettiva con ky(request.url, ...).
Quindi la sequenza era:
Questa è l'intera vulnerabilità.
La distinzione importante è dove è stata presa la decisione di fiducia.
Molti bug sembrano piccoli se li descrivi male.
Se descrivi questo come:
"il filtro del nome host era incompleto"
sembra un problema di qualità.
Questo non è il vero problema.
Il vero problema era:
Questa non è una debolezza di filtraggio estetica.
È un fallimento del confine di fiducia.
E poiché l'esecutore HTTP registrava i dati di risposta nei log di esecuzione, il problema non era nemmeno cieco nei casi più forti.
Quindi non era solo:
Era:
Questa è una vera vulnerabilità SSRF.
Ho usato due livelli di prova perché dimostravano due cose diverse.
La prima PoC isolava pulitamente la causa principale.
Ho usato un piccolo harness locale che:
127.0.0.1http://ssrf-repro.example:18080/...ssrf-repro.example si risolvesse in 127.0.0.1Questo dimostrava l'esatto difetto:
L'output catturato mostrava:
Questo dimostrava direttamente la lacuna di convalida.
La seconda PoC mostrava il bug attraverso il percorso di funzionalità effettivo che conta.
La riproduzione più semplice era:
Webhook che punta a quel nome host benigno