système : OPÉRATIONNEL
← retour à tous les hacks
INFRASTRUCTURE CRITICAL NEW

Le broker ZMQ de SGLang : RCE non authentifiée par désérialisation pickle

Trois CVE divulguées le 12 mars 2026 transforment les appels pickle.loads() de SGLang en exécution de code à distance non authentifiée. Le correctif est arrivé en v0.5.10 — mais la vraie leçon, c'est que pickle sur une socket réseau est une RCE par conception.

2026-06-04 // 7 min affects: sglang, multimodal-llm-serving, ai-inference-infrastructure

De quoi s’agit-il ?

Le 12 mars 2026, le chercheur d’Orca Security Igor Stepansky et le CERT Coordination Center ont co-publié trois vulnérabilités dans SGLang, un framework open source très répandu pour servir des grands modèles de langage et des modèles multimodaux (il expose Qwen, DeepSeek, Mistral, Skywork et d’autres derrière une API compatible OpenAI). Deux d’entre elles — CVE-2026-3059 et CVE-2026-3060, toutes deux notées CVSS 9.8 dans la GitHub Advisory Database — permettent une exécution de code à distance non authentifiée contre tout déploiement SGLang exposant la fonctionnalité concernée au réseau. Une troisième, CVE-2026-3989 (CVSS 7.8), est une variante locale / par ingénierie sociale dans un script de relecture de dump. Toutes trois partagent une même cause racine : des données non fiables passées au module pickle de Python. Le correctif est arrivé en version 0.5.10.

C’est la même classe de vulnérabilité que la RCE pickle de LightLLM et elle s’inscrit dans la vague 2026 de CVE d’infrastructure IA, aux côtés de la SQLi pré-auth de LiteLLM et de la SSRF de LMDeploy. Nous la traitons parce que le schéma se répète, et que la mitigation est structurelle, pas cosmétique.

Comment ça marche

Le format pickle de Python ne stocke pas que des données — il stocke des instructions de reconstruction d’objets, et ces instructions s’exécutent pendant la désérialisation. Donc pickle.loads() sur des octets contrôlés par un attaquant est, par définition, une exécution de code arbitraire. La primitive classique est un objet dont la méthode __reduce__ renvoie un appel à os.system ou subprocess ; rien d’exotique n’est requis, raison pour laquelle aucun payload n’est reproduit ici.

SGLang exposait pickle.loads() sur des chemins accessibles depuis le réseau, sans authentification :

CVE        Composant                          Vecteur / prérequis
---------  ---------------------------------  ----------------------------------------
3059       Module de génération multimodale   RCE non auth. via le broker ZMQ ;
(9.8)                                          requiert la génération multimodale active
3060       Désagrégation parallèle d'encodeur RCE non auth. via le module de
(9.8)                                          désagrégation ; requiert celui-ci actif
3989       replay_request_dump.py             pickle.load() d'un .pkl fourni par
(7.8)                                          l'attaquant ; nécessite un contrôle local

Selon le CERT/CC, pour les deux failles critiques, « si un attaquant connaît le port TCP sur lequel le broker ZMQ écoute et peut envoyer des requêtes au serveur, il peut exploiter la vulnérabilité en envoyant un fichier pickle malveillant au broker, qui le désérialisera ». Aucun prompt, aucune interaction avec le modèle, aucun identifiant — un seul message forgé sur la socket ZeroMQ suffit. La faiblesse est classée CWE-502, désérialisation de données non fiables. CVE-2026-3989 est plus restreinte : l’utilitaire replay_request_dump.py appelle pickle.load() sur un fichier de dump sans validation ; un attaquant capable d’écrire dans le répertoire de dumps (ou d’amener par ingénierie sociale un opérateur à relire un .pkl malveillant) obtient l’exécution de code sur l’hôte exécutant le script.

Pourquoi c’est important

Un serveur d’inférence n’est pas une cible de faible valeur. Il tourne typiquement sur des hôtes GPU disposant d’une large portée réseau interne, héberge les poids des modèles et traite les prompts et documents que vos applications lui envoient. Une exécution de code dans le processus SGLang peut mener à une compromission de l’hôte, du mouvement latéral, de l’exfiltration de données ou un déni de service. Comme les deux failles critiques sont pré-authentification et déclenchées par un message brut sur la socket, tout déploiement ayant placé son broker ZMQ sur une interface accessible était exploitable par quiconque pouvait lui acheminer un paquet.

Deux schémas méritent attention. D’abord, la tuyauterie ZMQ/IPC de l’inférence distribuée est une frontière de confiance non authentifiée que les équipes oublient régulièrement — elle a été conçue pour la communication intra-cluster, pas pour des réseaux hostiles. Ensuite, pickle réapparaît sans cesse dans la pile IA parce qu’il est la voie de moindre résistance pour déplacer des objets Python (tenseurs, requêtes, dumps) entre processus. À ce jour, aucune exploitation dans la nature n’a été signalée, mais le score EPSS et la trivialité de la primitive d’exploitation en font des candidates de choix pour du scan opportuniste.

Défenses

  • Passez à SGLang v0.5.10 ou ultérieure, que le CERT/CC indique comme la version corrigée. Attention au décalage : la GitHub Advisory Database affiche encore les versions <= 0.5.9 comme affectées sans version corrigée renseignée — vérifiez sur la release amont plutôt que sur ce champ de la base d’avis.
  • N’exposez jamais le broker ZMQ à des réseaux non fiables. Liez les sockets internes à l’inférence à 127.0.0.1 ou à une interface privée, et placez segmentation réseau et contrôles d’accès entre le port du broker et tout ce qui est routable. Cette seule étape neutralise CVE-2026-3059 et CVE-2026-3060, quelle que soit la version.
  • Traitez pickle sur une socket comme une RCE. Là où vous contrôlez la sérialisation, remplacez pickle par un format de données pures — JSON ou msgpack — afin qu’un payload malformé ne puisse pas faire passer du code. C’est le correctif structurel recommandé par le CERT/CC.
  • Verrouillez la gestion des dumps pour CVE-2026-3989 : restreignez l’accès en écriture aux répertoires de dumps, et n’exécutez jamais replay_request_dump.py sur un .pkl que vous n’avez pas généré.
  • Surveillez l’hôte d’inférence. Guettez les connexions TCP entrantes inattendues vers le port ZMQ, les processus enfants inattendus issus du processus Python de SGLang, la création de fichiers dans des emplacements inhabituels et les connexions sortantes vers des destinations inconnues — les indicateurs signalés par le CERT/CC et Orca.
  • Inventoriez votre couche de service. SGLang, vLLM, LightLLM, LMDeploy et outils similaires sont souvent déployés par les équipes ML hors du circuit de revue de sécurité. Trouvez ceux exposés au réseau avant qu’un scanner ne le fasse.

État

ÉlémentDateStatut
Note de vulnérabilité CERT/CC (VU#665416)12 mars 2026Public
Blog de divulgation Orca Security12 mars 2026Public
Entrées GitHub Advisory DB (CVE-2026-3059/3060)12 mars 2026Public, CVSS 9.8
Dernière révision de la note CERT/CC7 avr. 2026Indique v0.5.10 comme corrigée
Couverture (The Hacker News)17 mars 2026Public
Exploitation dans la natureAucune signalée à la divulgation

Le constat est sans détour : pickle.loads() sur une socket accessible depuis le réseau n’est pas un bug à corriger une fois, c’est un anti-pattern à supprimer. Le correctif est v0.5.10 ; la leçon est que tout composant d’inférence IA à l’écoute sur un port doit être traité comme une frontière d’authentification et de désérialisation dès le premier jour.

Sources