La campagne Load/Mine : 31 dépôts piégés sur Hugging Face
Le 29 octobre 2026, les chercheurs de Pluto Security (Shaked Chen, Eitan Chassid et Yotam Perkal) ont publié un rapport détaillant une campagne baptisée Load/Mine (source : Pluto Security). Trente et un dépôts malveillants répartis sur sept comptes Hugging Face ont été identifiés, cumulant plus de 32 000 téléchargements. Un seul dépôt, MENXIANGYU/qwen2-tiny, concentrait 28 412 téléchargements au 28 octobre. Objectif des attaquants : détourner les GPU des serveurs d'inférence auto-hébergés pour miner de la cryptomonnaie (PRL et Monero).
Si vous hébergez un service d'inférence IA sur un VPS Linux ou un serveur dédié avec GPU, cette campagne vous concerne directement. Que votre serveur tourne sous Ubuntu, Debian ou toute autre distribution Unix, les techniques employées ciblent le processus de chargement de modèles via la bibliothèque Python Transformers. Cet article détaille le mécanisme d'infection, les indicateurs de compromission (IOC) publiés et les mesures à appliquer sur votre infrastructure.
Comment trust_remote_code ouvre la porte au malware
La bibliothèque Python Transformers de Hugging Face permet de charger un modèle avec la fonction AutoModelForCausalLM.from_pretrained(). Lorsque le paramètre trust_remote_code=True est passé, Transformers lit le champ auto_map du fichier config.json du dépôt, télécharge le fichier Python référencé (par exemple le nom du fichier modeling_evil2.py) et l'exécute via importlib. Toutes les instructions au niveau du module (hors classe) s'exécutent avant même le chargement des poids du modèle, avec les privilèges complets de l'utilisateur qui lance le processus.
Ce n'est pas une faille dans le package Transformers : c'est un comportement documenté, conçu pour permettre aux extensions personnalisées de fonctionner. Mais sur un serveur de production, activer trust_remote_code revient à exécuter du code arbitraire téléchargé depuis un dépôt public, avec un accès direct au GPU, au processeur, à la RAM et au système de fichiers.
La vulnérabilité CVE-2026-22807 dans vLLM (versions 0.10.1 à 0.13.x) illustre ce risque : ces versions chargeaient les modules auto_map sans même vérifier le flag trust_remote_code. Le code malveillant s'exécutait au démarrage du serveur, quelle que soit la configuration. La correction a été intégrée dans vLLM 0.14.0.
Chaîne d'attaque détaillée
Les chercheurs de Pluto Security ont reconstitué la séquence d'infection en plusieurs phases. Le nom du fichier malveillant varie selon la vague (modeling_evil.py, modeling_evil2.py, modeling_parasit.py), mais la chaîne d'exécution reste identique.
| Phase | Action |
|---|---|
| 1. Exécution initiale | Le fichier config.json du dépôt pointe vers modeling_evil2.EvilModel. Le chargement du module exécute le code Python au niveau supérieur du fichier. |
| 2. Persistance | Un script watchdog /tmp/.cch/svc.py est créé. Il relance le mineur toutes les 120 secondes. Des entrées sont ajoutées dans /root/.bashrc et /root/.profile pour survivre aux redémarrages du serveur. |
| 3. Mineur en mémoire | Le binaire syscore.bin (40,6 Mo d'espace disque, compressé UPX avec marqueurs modifiés de UPX! en PEK!) est chargé en mémoire via memfd_create("kworker") et exécuté avec fexecve(). Le processus se déguise en thread noyau [kworker/u20:1]. |
| 4. Élimination de concurrents | Le malware scanne /proc/*/cmdline et tue 13 mineurs concurrents connus pour monopoliser le GPU. |
| 5. Rapport d'état | L'état de l'infection est encodé en base32 dans des noms de modèles du registre Xinference local (codes : B=démarrage, P=binaire obtenu, OK=lancement mémoire vérifié, H=heartbeat avec utilisation GPU). |
| 6. Reverse shell (vague 2) | Reconnexion persistante vers l'adresse IP 212.32.253.3 sur les ports 443 et 9443, offrant un accès shell complet à l'attaquant. |
| 7. Évasion de conteneur | Un script publié 8,5 heures après la divulgation active les volumes LVM, monte les disques de l'hôte et plante un accès root sur la machine physique sous-jacente (cible : /var/lib/gpustack). |
Serveurs d'inférence ciblés
La campagne vise spécifiquement les plateformes d'inférence auto-hébergées sur des serveurs GPU. Tout hébergeur ou administrateur exploitant ces environnements d'inférence est potentiellement concerné.
- Xinference : le mineur utilise le registre de modèles Xinference pour rapporter son état et cible
/home/xinference/.ssh/authorized_keyspour la persistance SSH ; - GPUStack : le script d'évasion de conteneur cible le répertoire
/var/lib/gpustackpour obtenir un accès root sur l'hôte ; - vLLM : exploité via CVE-2026-22807, le code s'exécute sans vérification du flag
trust_remote_code(corrigé dans la version 0.14.0) ; - LLaMA-Factory : certains dépôts ciblent spécifiquement cette plateforme.
Si vous faites tourner l'une de ces plateformes sur un serveur dédié ou un VPS avec GPU, vérifiez immédiatement les indicateurs de compromission ci-dessous.
Indicateurs de compromission (IOC)
Pluto Security a publié une liste complète d'IOC. Ouvrez un terminal SSH sur votre serveur et recherchez les éléments suivants en ligne de commande.
Fichiers sur le système
# Répertoire principal du mineur
sudo ls -la /tmp/.cch/ 2>/dev/null # svc.py, sync, syscore.bin
sudo ls -la /tmp/.cchx/ 2>/dev/null
sudo ls -la /tmp/.kitsd/ 2>/dev/null
sudo ls -la /tmp/.cache-hf/ 2>/dev/null # g20.py
# Watchdogs MONIADF-2
sudo ls -la /root/.mx /tmp/.mx /var/tmp/.mx /dev/shm/.mx 2>/dev/null
# Crontab malveillante
sudo ls -la /etc/cron.d/.sync-helper 2>/dev/nullClé SSH backdoor
sudo grep "qx-5090-op" ~/.ssh/authorized_keys /root/.ssh/authorized_keys \
/home/xinference/.ssh/authorized_keys 2>/dev/nullLa clé publique déposée est : ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDYjYyvcEJW5ZVgsESyZE5uxqSwN2vmd5asrWICeHxu1 qx-5090-op
Processus suspects
# Processus mineur déguisé en thread noyau
ps aux | grep -E "\[kworker/u20:1\]|svc\.py|krxXJ2PKQW"
# Connexions vers les adresses IP de commande et contrôle (C2)
ss -tnp | grep -E "212\.32\.253\.3|38\.55\.133\.49|8\.137\.187\.63|103\.97\.176\.121"Hash SHA-256 du binaire mineur (vague 2)
88f4b95a1c3d0a0d9638dc6e69f5bbc9ce0e1b92d069a0e404f60fa5397ee020Calculez le hash d'un fichier suspect avec sha256sum /chemin/vers/fichier dans le terminal et comparez-le à cette empreinte.
Vérifier si votre serveur est compromis
Connectez-vous en SSH à votre serveur d'inférence depuis un terminal et exécutez cette séquence de vérifications en ligne de commande. Les commandes fonctionnent sur Ubuntu, Debian et toute distribution Unix.
# 1. Chercher les répertoires du mineur
for d in /tmp/.cch /tmp/.cchx /tmp/.kitsd /tmp/.cache-hf /root/.hl; do
[ -d "$d" ] && echo "SUSPECT : $d existe"
done
# 2. Chercher la clé SSH backdoor
sudo grep -r "qx-5090-op" /root/.ssh/ /home/*/.ssh/ 2>/dev/null
# 3. Vérifier les entrées bashrc malveillantes
grep -l "\.cch/svc\.py" /root/.bashrc /root/.profile ~/.bashrc 2>/dev/null
# 4. Chercher le cron caché
sudo cat /etc/cron.d/.sync-helper 2>/dev/null
# 5. Processus mineur actif (consommation processeur et RAM)
ps aux | grep -v grep | grep -E "kworker.*krxXJ2PKQW|svc\.py|syscore"
# 6. Connexions réseau vers les C2
ss -tnp | grep -E "212\.32\.253\.3|38\.55\.133\.49|8\.137\.187\.63"Si l'une de ces vérifications renvoie un résultat, votre serveur est compromis. Passez immédiatement au nettoyage et à la réinstallation.
Nettoyer un serveur compromis
En cas de compromission confirmée, effectuez d'abord une sauvegarde forensique complète de l'état actuel (disques, logs, fichiers de configuration) à des fins d'analyse, puis procédez dans cet ordre.
- Isoler le serveur : coupez la connectivité réseau ou configurez un firewall restrictif (configurer nftables). Bloquez les adresses IP des serveurs C2 avec des règles nftables ou iptables. Ajoutez un blocage DNS vers les domaines de commande et contrôle pour empêcher toute reconnexion.
- Tuer les processus malveillants : identifiez le PID du faux
[kworker/u20:1]et du watchdogsvc.pyavecps aux, puis terminez-les avecsudo kill -9 <PID>. - Supprimer les fichiers : effacez les répertoires du mineur avec
sudo rm -rf /tmp/.cch/ /tmp/.cchx/ /tmp/.kitsd/ /tmp/.cache-hf/. Supprimez/etc/cron.d/.sync-helperet tout fichier watchdog dans/root/.mx,/tmp/.mx,/var/tmp/.mx,/dev/shm/.mx. - Retirer la clé SSH backdoor : supprimez la ligne contenant
qx-5090-opde tous les fichiersauthorized_keys. - Nettoyer les scripts de démarrage : retirez les lignes contenant
.cch/svc.pyde/root/.bashrc,/root/.profileet de tout fichier shell de démarrage. - Redémarrer les services : après le nettoyage, redémarrez le service SSH avec
sudo systemctl restart sshdet vérifiez que le mineur ne se relance pas. Surveillez la consommation du processeur, de la RAM et du GPU pendant 24 heures. - Régénérer les clés SSH du serveur et déployer de nouvelles clés (configurer une clé SSH sur VPS Linux).
- Réinstaller si possible : sur un serveur de production, la réinstallation complète reste la seule garantie. Restaurez depuis une sauvegarde antérieure à la date du premier téléchargement suspect. Si vous ne disposez pas de sauvegardes récentes, planifiez une migration vers un serveur propre.
Isoler l'environnement d'exécution des modèles
La meilleure défense contre l'exécution de code malveillant via trust_remote_code est l'isolation de l'environnement dans lequel les modèles sont chargés. Plusieurs niveaux de virtualisation s'offrent à l'administrateur.
Environnement virtuel Python
Créez un environnement virtuel dédié pour chaque projet d'inférence. Cela isole les packages Python (Transformers, PyTorch, les extensions tierces) du système hôte. En cas de compromission, seul l'environnement virtuel est touché, pas les packages système.
python3 -m venv ~/inference-env
source ~/inference-env/bin/activate
pip install transformers torch safetensorsConteneur Docker isolé
Exécutez le service d'inférence dans un conteneur Docker avec des restrictions de sécurité. Le conteneur limite l'accès au système de fichiers de l'hôte, au réseau et aux processus. Pour les serveurs GPU, utilisez le runtime NVIDIA avec des limites de ressources (processeur, RAM, espace disque) :
docker run --gpus all --security-opt=no-new-privileges \
--user 1000:1000 --read-only --tmpfs /tmp \
--memory=16g --cpus=4 \
-v /chemin/modeles:/models:ro \
mon-image-inferenceConsultez notre guide installer Docker sur un VPS pour la mise en place initiale.
Machine virtuelle dédiée
Pour une isolation maximale, déployez le service d'inférence dans une machine virtuelle dédiée. La virtualisation matérielle (KVM, QEMU) empêche toute évasion vers l'hôte, y compris les techniques d'évasion de conteneur utilisées dans la vague 2 de Load/Mine. C'est la solution recommandée pour les environnements virtuels de production hébergeant des données sensibles.
Protéger un serveur d'inférence en production
Cette campagne exploite un paramètre activé volontairement par l'administrateur. Voici les mesures à appliquer sur tout serveur d'inférence GPU auto-hébergé, que vous soyez hébergeur ou administrateur indépendant.
- Ne jamais activer
trust_remote_code=Truesur un serveur de production. Si un modèle l'exige, auditez le code Python du dépôt avant de l'exécuter. Vérifiez le contenu deconfig.json(champauto_map) et le nom du fichier de chaque script.pyréférencé. - Mettre à jour vLLM vers la version 0.14.0 ou supérieure pour corriger CVE-2026-22807. Vérifiez la version installée dans le terminal avec
pip show vllm. - Configurer un firewall pour bloquer les connexions sortantes vers les adresses IP de commande et contrôle connues. Ajoutez des règles nftables ou iptables pour bloquer
212.32.253.3,38.55.133.49,8.137.187.63et103.97.176.121(configurer nftables). - Surveiller les ressources du serveur : un mineur consomme 100 % du GPU, fait monter la charge processeur et la consommation de RAM. Configurez des alertes avec htop/btop ou via la ligne de commande avec
nvidia-smi --query-gpu=utilization.gpu --format=csv -l 5. Vérifiez aussi l'espace disque, car le binaire mineur pèse 40,6 Mo. - Planifier des sauvegardes régulières : configurez un backup automatique de votre serveur et de vos modèles vérifiés. En cas de compromission, une sauvegarde saine permet de réinstaller rapidement (sauvegarder avec rsync).
- Automatiser les mises à jour de sécurité du système d'exploitation et des packages Python (mises à jour automatiques sur Ubuntu).
- Auditer régulièrement
authorized_keyset les tâches cron sur chaque serveur (sécuriser SSH sur VPS Linux). Vérifiez aussi les extensions et les packages Python installés avecpip listdepuis le terminal.
Chronologie de la campagne
| Date | Événement |
|---|---|
| 29 avril 2026 | Création du compte Hugging Face hhzz667. |
| 21 septembre | Vague 1 : le compte hhzz667 crée qwen2-shell, un dépôt contenant une backdoor SSH de 37 lignes. |
| 21-22 septembre | Escalade vers un mineur complet avec modeling_evil.py (305 lignes). |
| 12 octobre | Le compte jetable dsxk4mr8tq copie le code malveillant et est détecté par un scanner. |
| 20-25 octobre | Vague 2 : 19 dépôts sur 5 nouveaux comptes, avec reverse shell, payloads protégés par adresse IP et scripts d'évasion de conteneur. |
| 29 octobre | Publication du rapport Load/Mine par Pluto Security. Huit heures plus tard, un script d'évasion de conteneur cible GPUStack. |
FiveM
Minecraft
Rust
RedM
Hytale