El broker ZMQ de SGLang: RCE no autenticada por deserialización de pickle
Tres CVE divulgadas el 12 de marzo de 2026 convierten las llamadas pickle.loads() de SGLang en ejecución remota de código sin autenticación. El parche llegó en la v0.5.10, pero la verdadera lección es que pickle sobre un socket de red es RCE por diseño.
¿Qué es esto?
El 12 de marzo de 2026, el investigador de Orca Security Igor Stepansky y el CERT Coordination Center publicaron conjuntamente tres vulnerabilidades en SGLang, un framework de código abierto muy utilizado para servir grandes modelos de lenguaje y modelos multimodales (expone Qwen, DeepSeek, Mistral, Skywork y otros tras una API compatible con OpenAI). Dos de ellas — CVE-2026-3059 y CVE-2026-3060, ambas con CVSS 9.8 en la GitHub Advisory Database — permiten ejecución remota de código sin autenticación contra cualquier despliegue de SGLang que exponga la función afectada a la red. Una tercera, CVE-2026-3989 (CVSS 7.8), es una variante local / por ingeniería social en un script de reproducción de volcados. Las tres comparten una misma causa raíz: datos no confiables pasados al módulo pickle de Python. El parche llegó en la versión 0.5.10.
Es la misma clase de vulnerabilidad que la RCE de pickle en LightLLM y se enmarca en la oleada de 2026 de CVE de infraestructura de IA, junto con la SQLi previa a la autenticación de LiteLLM y la SSRF de LMDeploy. La cubrimos porque el patrón se repite y la mitigación es estructural, no cosmética.
Cómo funciona
El formato pickle de Python no solo almacena datos: almacena instrucciones para reconstruir objetos, y esas instrucciones se ejecutan durante la deserialización. Por tanto, pickle.loads() sobre bytes controlados por un atacante es, por definición, ejecución de código arbitrario. La primitiva clásica es un objeto cuyo método __reduce__ devuelve una llamada a os.system o subprocess; no se requiere nada exótico, razón por la cual aquí no se reproduce ningún payload.
SGLang exponía pickle.loads() en rutas accesibles desde la red, sin autenticación:
CVE Componente Vector / requisito previo
--------- --------------------------------- ----------------------------------------
3059 Módulo de generación multimodal RCE no auth. vía el broker ZMQ;
(9.8) requiere la generación multimodal activa
3060 Desagregación paralela de encoder RCE no auth. vía el módulo de
(9.8) desagregación; requiere este activo
3989 replay_request_dump.py pickle.load() de un .pkl provisto por
(7.8) el atacante; necesita control local
Según el CERT/CC, para los dos fallos críticos, «si un atacante conoce el puerto TCP en el que escucha el broker ZMQ y puede enviar solicitudes al servidor, puede explotar la vulnerabilidad enviando un archivo pickle malicioso al broker, que lo deserializará». Sin prompt, sin interacción con el modelo, sin credenciales: basta un único mensaje manipulado en el socket ZeroMQ. La debilidad está catalogada como CWE-502, deserialización de datos no confiables. CVE-2026-3989 es más acotada: la utilidad replay_request_dump.py llama a pickle.load() sobre un archivo de volcado sin validación, de modo que un atacante con capacidad de escribir en el directorio de volcados (o de engañar a un operador para que reproduzca un .pkl malicioso) obtiene ejecución de código en el host que ejecuta el script.
Por qué importa
Un servidor de inferencia no es un objetivo de bajo valor. Suele ejecutarse en hosts con GPU que tienen amplio alcance en la red interna, alberga los pesos de los modelos y procesa los prompts y documentos que le envían tus aplicaciones. La ejecución de código en el proceso de SGLang puede derivar en compromiso del host, movimiento lateral, exfiltración de datos o denegación de servicio. Como los dos fallos críticos son previos a la autenticación y se activan con un mensaje en bruto en el socket, cualquier despliegue que situara su broker ZMQ en una interfaz alcanzable era explotable por cualquiera que pudiese encaminarle un paquete.
Dos patrones merecen atención. Primero, el cableado ZMQ/IPC de la inferencia distribuida es una frontera de confianza sin autenticación que los equipos olvidan con frecuencia: se diseñó para la comunicación dentro del clúster, no para redes hostiles. Segundo, pickle reaparece una y otra vez en la pila de IA porque es la vía de menor resistencia para mover objetos de Python (tensores, solicitudes, volcados) entre procesos. Hasta la fecha no se ha reportado explotación en el mundo real, pero la puntuación EPSS y la trivialidad de la primitiva de explotación las convierten en candidatas idóneas para el escaneo oportunista de Internet.
Defensas
- Actualiza a SGLang
v0.5.10o posterior, que el CERT/CC indica como la versión corregida. Atención al desfase: la GitHub Advisory Database sigue mostrando las versiones<= 0.5.9como afectadas sin versión parcheada registrada, así que verifica contra la release del proyecto en lugar de ese campo de la base de avisos. - Nunca expongas el broker ZMQ a redes no confiables. Vincula los sockets internos de la inferencia a
127.0.0.1o a una interfaz privada, y coloca segmentación de red y controles de acceso entre el puerto del broker y todo lo que sea enrutable. Este único paso neutraliza CVE-2026-3059 y CVE-2026-3060 con independencia de la versión. - Trata pickle sobre un socket como una RCE. Donde controles la serialización, sustituye
picklepor un formato solo de datos — JSON omsgpack— para que un payload mal formado no pueda colar código. Es la corrección estructural que recomienda el CERT/CC. - Asegura el manejo de volcados para CVE-2026-3989: restringe el acceso de escritura a los directorios de volcado y nunca ejecutes
replay_request_dump.pysobre un.pklque no hayas generado tú. - Monitoriza el host de inferencia. Vigila conexiones TCP entrantes inesperadas hacia el puerto ZMQ, procesos hijo inesperados generados por el proceso Python de SGLang, creación de archivos en ubicaciones inusuales y conexiones salientes hacia destinos desconocidos: los indicadores que señalan el CERT/CC y Orca.
- Inventaría tu capa de servicio. SGLang, vLLM, LightLLM, LMDeploy y herramientas similares suelen desplegarse por equipos de ML al margen de la revisión de seguridad estándar. Encuentra las expuestas a la red antes de que lo haga un escáner.
Estado
| Elemento | Fecha | Estado |
|---|---|---|
| Nota de vulnerabilidad CERT/CC (VU#665416) | 12 mar 2026 | Público |
| Blog de divulgación de Orca Security | 12 mar 2026 | Público |
| Entradas en GitHub Advisory DB (CVE-2026-3059/3060) | 12 mar 2026 | Público, CVSS 9.8 |
| Última revisión de la nota CERT/CC | 7 abr 2026 | Indica v0.5.10 como corregida |
| Cobertura (The Hacker News) | 17 mar 2026 | Público |
| Explotación en el mundo real | — | Ninguna reportada en la divulgación |
La conclusión es contundente: pickle.loads() sobre un socket accesible desde la red no es un fallo que se parchea una vez, es un antipatrón que debe eliminarse. El parche es v0.5.10; la lección es que todo componente de inferencia de IA que escuche en un puerto debe tratarse como una frontera de autenticación y deserialización desde el primer día.