
Ataques
CVE-2025-67635: DoS não autenticado no endpoint do plain CLI do Jenkins

Analista de segurança
Atualizado
12 de dez. de 2025
5 min
TL;DR:
O endpoint do plain CLI do Jenkins (
/cli?remoting=false) emparelha duas requisições POST (download/upload) por meio de um UUID deSessioncompartilhado e é acessível sem permissão Overall/Read.Dois bugs se combinam: Um
HashMapsem sincronização emCLIActionperde uma metade da sessão (race condition), e os loops de espera do protocolo CLI (ServerSideImpl.run,FullDuplexHttpService.upload) não têm timeout.Atacantes podem concluir suas chamadas HTTP em milissegundos enquanto deixam threads do Jetty bloqueadas por 15 segundos (janela da race condition) ou indefinidamente (protocolo abandonado), causando um DoS assimétrico em todo o controller.
Afeta core ≤ 2.540 e LTS ≤ 2.528.2 (CWE-362/CWE-404, CVSS: 7,5). Corrigido em 2.541 e 2.528.3 usando
ConcurrentHashMap, adicionando timeouts no handshake e fechando streams em caso de erro.Mitigue agora: Atualize, ou bloqueie o acesso ao endpoint do plain CLI a partir de redes não confiáveis e capture thread dumps para confirmar que não há threads travadas em
CLIAction$ServerSideImpl.runouFullDuplexHttpService.upload/download.
O que o endpoint faz
O CLI sem Remoting constrói um canal full-duplex a partir de duas requisições POST HTTP:
Lado download:
Side: download, abre/cli?remoting=false, o servidor escreve um byte e aguarda a metade uploadLado upload:
Side: upload, mesmo UUID deSession, fornece o input stream
hudson.cli.CLIAction conecta isso ao jenkins.util.FullDuplexHttpService, armazenando as sessões ativas em um registro compartilhado entre requisições.
Causa raiz #1: Registro de sessões sem sincronização (race condition)
CLIAction mantém o mapa de sessões em um HashMap simples compartilhado por todas as threads de requisição:
FullDuplexHttpService.Response.generateResponse chama services.put(uuid, service) para o lado download e services.get(uuid) para o lado upload. Como HashMap não é thread-safe, puts/gets concorrentes sob carga podem
retornar
nullpara um lado download válido;perder entradas durante um resize;
deixar threads de download dentro de
FullDuplexHttpService.downloadaguardando até 15 segundos por um upload que já chegou.
O resultado: Cada par afetado pela race condition bloqueia uma thread do servlet durante todo o timeout enquanto os sockets do atacante se fecham imediatamente, causando um DoS assimétrico e violando o requisito de segurança “Tornar fluxos de lógica crítica thread safe”.
Causa raiz #2: Timeouts ausentes no protocolo (bloqueio determinístico)
Mesmo quando as duas metades se emparelham corretamente, o handshake do protocolo pode entrar em deadlock porque nenhum lado tem timeout:
Se o cliente encerrar a conexão antes de enviar frames CLI, a thread de download fica bloqueada em ServerSideImpl.run() e a thread de upload fica bloqueada em upload() sem timeout, consumindo duas threads do Jetty por tentativa até esgotar o controller.
Notas de exploração
Ambos os vetores exigem apenas conectividade de rede ao /cli:
Cenário A (race condition): Dispare pares download/upload sobrepostos com leve jitter para que o lado upload ocasionalmente receba
null. As threads se acumulam emFullDuplexHttpService.downloadpor cerca de 15 segundos cada.Cenário B (abandono): Abra ambas as metades, deixe-as emparelhar, e depois feche sem enviar frames CLI. As threads ficam em
CLIAction$ServerSideImpl.runeFullDuplexHttpService.uploadindefinidamente, sem necessidade de janela de timing.
Abaixo estão as PoCs exatas compartilhadas com a equipe de segurança do Jenkins:
PoC: racecond_a.py (race no HashMap, dois downloads por UUID)
PoC: racecond_b.py (abandono de protocolo, bloqueio determinístico)
Evidência
Thread dump (Cenário B, controller de teste Jenkins 2.516.2): Travados exatamente nos call sites sem timeout:
Evidência em vídeo: Reprodução completa do crash contra um controller recém-instalado.
Em um build vulnerável, você verá dezenas de threads de requisição aguardando nesses call sites, e chamadas CLI regulares começarão a dar timeout.
Impacto
DoS não autenticado: Não é necessário Overall/Read para acessar
/cli?remoting=falseBaixo custo para o atacante: Os sockets fecham imediatamente, o servidor retém o trabalho (15 segundos por tentativa de race, infinito para abandono)
Degradação de todo o controller: As threads do servlet e os fluxos de E/S se acumulam, outros endpoints começam a dar timeout
Detalhes do patch
Commit principal: efa1816
CLIActionagora armazena as sessões em umConcurrentHashMap, eliminando as perdas doHashMapcom race conditions que potencializavam o DoS assimétrico.ServerSideImpl.runeFullDuplexHttpService.uploadadotaram waits limitados porCONNECTION_TIMEOUTcom wake-ups de 1 segundo e logs de DEBUG, de modo que handshakes abandonados se desfazem em vez de estacionar threads.PlainCLIProtocolagora sempre chamaside.handleClose()em um blocofinally, garantindo que ambas as metades se desmontem mesmo diante de erros de leitura ou exceções de runtime.Foi adicionada cobertura de regressão em
Security3630Test(JUnit 5): Reduz o timeout do CLI para testes, exercita a race condition anterior com invocações CLI concorrentes e verifica que as threads são liberadas após streams truncados.Efeito final: O emparelhamento de download/upload do CLI agora falha rápido e libera threads do Jetty em vez de bloquear indefinidamente aguardando contrapartes ausentes.
As alterações restauram a conformidade do path do CLI full-duplex com o requisito “Tornar os fluxos de lógica crítica thread safe”.
Referências do CVE e advisory
SECURITY-3630 recebeu o identificador CVE-2025-67635 (CVSS 3.1: AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H). Veja o registro do CNA em cve.org e a entrada do NIST no NVD para metadados canônicos.
Write-up oficial do Jenkins: Jenkins Security Advisory 2025-12-10: SECURITY-3630.
Correção e hardening
Se você não puder atualizar imediatamente, faça o seguinte:
Desabilite ou bloqueie o acesso ao endpoint do plain CLI a partir de redes não confiáveis; prefira o WebSocket CLI com autenticação adequada.
Reduza os limites de threads do Jetty somente como último recurso (não elimina o bug).
Monitore thread dumps buscando estados de wait em
CLIAction$ServerSideImpl.runeFullDuplexHttpService.upload/download.
Indicadores de comprometimento
Mensagens repetidas de
IOException: No download side found for <uuid>nos logs.Thread dumps mostrando muitos
TIMED_WAITINGemFullDuplexHttpService.downloadouWAITINGemCLIAction$ServerSideImpl.run/FullDuplexHttpService.upload.Picos de requisições a
/cli?remoting=falsesem headers de autenticação.
Aplique o patch imediatamente. Este é um path de DoS fácil e acessível pela rede em instalações de Jenkins com configuração padrão.
Get started with Fluid Attacks' PTaaS right now
Assine nossa newsletter
Mantenha-se atualizado sobre nossos próximos eventos e os últimos posts do blog, advisories e outros recursos interessantes.
Outros posts



















