
Ataques
CVE-2025-67635: DoS no autenticado en el endpoint full-duplex de Jenkins CLI

Analista de seguridad
Actualizado
12 dic 2025
5 min
TL;DR:
El endpoint del plain CLI de Jenkins (
/cli?remoting=false) empareja dos peticiones POST (download/upload) a través de un UUID deSessioncompartido y es accesible sin permisos Overall/Read.Se encadenan dos bugs: Un
HashMapno sincronizado enCLIActionpierde una mitad de la sesión (race condition), y los loops de espera del protocolo CLI (ServerSideImpl.run,FullDuplexHttpService.upload) no tienen timeout.Un atacante puede finalizar sus llamadas HTTP en milisegundos mientras dejan threads de Jetty durante 15 segundos (ventana de la race condition) o indefinidamente (protocolo abandonado), causando DoS asimétrico en todo el controller.
Afecta a core ≤ 2.540 y LTS ≤ 2.528.2 (CWE-362/CWE-404, CVSS: 7,5). Se solucionó en 2.541 y 2.528.3 usando
ConcurrentHashMap, agregando timeouts en el handshake y cerrando streams en caso de error.¿Cómo mitigarlo ahora mismo? Actualiza, o bloquea el acceso al endpoint del plain CLI desde redes no confiables y captura thread dumps para confirmar que no haya threads atascados en
CLIAction$ServerSideImpl.runoFullDuplexHttpService.upload/download.
¿Qué hace el endpoint?
El CLI sin Remoting construye un canal de full-duplex a partir de dos POSTs de HTTP:
Lado download:
Side: download, abre/cli?remoting=false, el servidor escribe un byte y espera la mitad de uploadLado de carga:
Side: upload, mismo UUID deSession, provee el input stream
hudson.cli.CLIAction conecta esto con jenkins.util.FullDuplexHttpService, almacenando las sesiones activas en un registro común entre peticiones.
Raíz del problema #1: Registro de sesiones no sincronizado (condición de carrera)
CLIAction mantiene el mapa de sesión en un HashMap simple compartido por todos los hilos de solicitud:
FullDuplexHttpService.Response.generateResponse llama a services.put(uuid, service) para el lado de descarga, y services.get(uuid) para el lado de carga. Debido a que HashMap no es seguro para hilos, las entradas/recibos concurrentes bajo carga pueden
devolver
nullpara un lado de descarga válido;caer entradas durante un redimensionamiento;
dejar hilos de descarga dentro de
FullDuplexHttpService.downloadesperando hasta 15s por una carga que ya había llegado.
El resultado: Cada par en carrera ocupa un hilo de servlet durante todo el tiempo de espera mientras los sockets del atacante se cierran de inmediato, causando un DoS asimétrico y violando el requisito de seguridad “Hacer que los flujos de lógica crítica sean seguros para hilos”.
Raíz del problema #2: Faltan tiempos de espera del protocolo (bloqueo determinista)
Aún cuando las dos mitades se emparejan correctamente, el apretón de manos del protocolo puede bloquearse porque ninguno de los lados caduca:
Si el cliente corta la conexión antes de enviar los cuadros CLI, el hilo de descarga se bloquea en ServerSideImpl.run() y el hilo de carga se bloquea en upload() sin tiempo de espera, consumiendo dos hilos de Jetty por intento hasta que el controlador se agote.
Notas de explotación
Ambos vectores requieren solo accesibilidad de red a /cli:
Escenario A (condición de carrera): Dispare pares de descarga/carga superpuestos con ligera variación para que la mitad de carga ocasionalmente vea
null. Los hilos se acumulan enFullDuplexHttpService.downloaddurante ~15s cada uno.Escenario B (abandono): abre ambas mitades, déjalas emparejar, luego cierra sin enviar cuadros CLI. Los hilos permanecen en
CLIAction$ServerSideImpl.runy enFullDuplexHttpService.uploadindefinidamente, sin ventana de temporización necesaria.
A continuación se presentan los PoCs exactos compartidos con el equipo de seguridad de Jenkins:
PoC: racecond_a.py ( carrera de HashMap, dos descargas por UUID)
PoC: racecond_b.py (abandono del protocolo, bloqueo determinista)
evidencia
Dump de hilos (Escenario B, controlador de prueba Jenkins 2.516.2): Atascado en los sitios de llamada exactos sin tiempo de espera:
evidencia en video: Reproducción de caos end-to-end contra un controlador fresco:
En una construcción vulnerable, verás docenas de hilos de solicitud esperando en esos sitios de llamada, y las llamadas CLI regulares comienzan a agotar el tiempo.
Impacto
DoS no autenticado: no se requiere Overall/Read para acceder a
/cli?remoting=falseCoste bajo para el atacante: Los sockets se cierran de inmediato, el servidor sostiene el trabajo (15s por intento de carrera, infinito por abandono)
Degradación en todo el controlador: Los hilos de servlet y los flujos de E/S se acumulan, otros puntos de acceso agotan el tiempo
Detalles de la corrección
Compromiso central: efa1816
CLIActionahora almacena sesiones en unConcurrentHashMap, eliminando las caídas delHashMapque alimentaban el DoS asimétrico.ServerSideImpl.runyFullDuplexHttpService.uploadadoptaron esperas limitadas porCONNECTION_TIMEOUTcon despertadores de 1s y registros de DEBUG, para que los apretones de manos abandonados se deshagan en lugar de aparcar hilos.PlainCLIProtocolsiempre llama aside.handleClose()en un bloquefinally, asegurando que ambas mitades se desmantelen incluso en errores de lectura o excepciones en tiempo de ejecución.La cobertura de regresión se encuentra en
Security3630Test(JUnit 5): reduce el tiempo de espera de CLI para pruebas, ejercita la carrera anterior con invocaciones CLI concurrentes y afirma que los hilos se liberan después de flujos truncados.Efecto neto: la emparejamiento de descarga/carga de CLI ahora falla rápidamente y libera hilos de Jetty en lugar de bloquear indefinidamente en contrapartes faltantes.
Los cambios devuelven la ruta CLI de dúplex completo a la conformidad con el requisito “Hacer que los flujos de lógica crítica sean seguros para hilos”.
Referencias CVE y asesoría
SECURITY-3630 se asignó CVE-2025-67635 (CVSS 3.1: AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H). Consulte el registro de CNA en cve.org y la entrada de NIST en NVD para metadatos canónicos.
Escrito oficial de Jenkins: Jenkins Security Advisory 2025-12-10: SECURITY-3630.
Corrección y fortalecimiento
Si no puede actualizar de inmediato, haga lo siguiente:
Desactive o encienda el firewall en el punto final de CLI plano, prefiera el CLI de WebSocket con autenticación adecuada.
Reduzca los límites de hilos de Jetty solo como último recurso (no elimina el error).
Monitoree los volcado de hilos para
CLIAction$ServerSideImpl.runyFullDuplexHttpService.upload/downloadestados de espera.
Indicadores de compromiso
Repetidos
IOException: No se encontró el lado de descarga para <uuid>en los registros.Descargas de hilos que muestran muchos
TIMED_WAITINGenFullDuplexHttpService.downloadoWAITINGenCLIAction$ServerSideImpl.run/FullDuplexHttpService.upload.Picos en solicitudes de
/cli?remoting=falseque carecen de encabezados de autenticación.
Corrija puntualmente. Este es un camino de DoS accesible por red en las implementaciones predeterminadas de Jenkins.
Get started with Fluid Attacks' PTaaS right now
Suscríbete a nuestro boletín
Mantente al día sobre nuestros próximos eventos y los últimos blog posts, advisories y otros recursos interesantes.
Otros posts


















