
End-to-end reproduction and cross-layer detection of CVE-2026-53576, the unauthenticated RCE in Kestra - taken past the base PoC to show how a common Docker-socket misconfiguration turns container-root into full host compromise.
Kestra, uma plataforma de orquestração de workflows de código aberto, distribuiu um filtro de autenticação que decidia se uma requisição precisava de credenciais verificando se a URL terminava com /configs - uma verificação destinada a expor um endpoint público inofensivo.
Como a verificação olhava apenas para o final da string, qualquer requisição cuja URL terminasse dessa forma ignorava completamente a autenticação, incluindo endpoints que criam e executam código arbitrário. O resultado: qualquer pessoa que consiga alcançar uma instância vulnerável do Kestra pela rede pode executar comandos como root sem nenhuma credencial, sem phishing, sem adivinhação de senha, sem necessidade de etapa de escalação de privilégios.
Neste exercício, essa única falha foi explorada de ponta a ponta contra uma instância de laboratório auto-hospedada:
Cada etapa foi capturada contra telemetria defensiva (IDS de rede, segurança de runtime do host, auditoria do Linux e logs do sistema).
Impacto nos negócios se não corrigido: comprometimento completo do host que executa o Kestra, não apenas da aplicação - e, por extensão, de qualquer outra coisa alcançável a partir desse host.
Correção: atualize para Kestra 1.0.45 / 1.3.21 ou posterior (o patch sozinho fecha a vulnerabilidade primária; as etapas de escalação e persistência exigem uma correção separada e independente - não monte o socket Docker em contêineres de aplicação, veja a Seção 8).
Este relatório documenta a CVE-2026-53576, uma vulnerabilidade de execução remota de código não autenticada com CVSS 10.0 no Kestra ≤1.3.20, causada por um bypass de autenticação por sufixo de caminho (AuthenticationFilter.java, endsWith("/configs")).
Um atacante que nomeia o namespace e o ID de um workflow como configs pode criar e executar comandos shell arbitrários sem credenciais, como root, dentro do contêiner Kestra. Corrigido em 1.0.45 e 1.3.21. O mesmo bug também foi reportado independentemente sob a CVE-2026-49869, que é o número listado no CISA KEV vinculado à exploração real em campo. Ambos devem ser citados juntos, já que fontes públicas e scanners podem referenciar qualquer um deles.
| Vulnerável | Kestra ≤ 1.3.20 (e pré-1.0.45 na linha 1.0.x) |
| Corrigida | 1.0.45 / 1.3.21+ |
| CVE | CVE-2026-53576 |
| Aviso gêmeo | CVE-2026-49869 - mesmo bug, listado no CISA KEV (em campo) |
| Data | Evento |
|---|---|
| 2026-06-02 | Kestra 1.3.21 lançado; changelog referencia um "potencial bypass de autenticação no filtro de autenticação" |
| 2026-06-03 | Kestra 1.0.45 lançado na linha 1.0.x |
| 2026-09-02 | CVE-2026-49869 (o aviso gêmeo) adicionado ao catálogo CISA KEV |
| 2026-09-22 a 09-24 | Esta reprodução em laboratório, construção de detecção e validação entre camadas |
Homelab auto-hospedado:
- Host Debian (hostname docker, kernel 6.12.107+deb13-amd64),
- Docker Engine 29.8.1.
- Kestra implantado como a imagem oficial kestra/kestra:v1.3.20, acessível através de um proxy reverso Caddy em kestra.int.atlasvec.com.
- Stack de telemetria em teste: Falco (runtime/eBPF, nível de host),
- Suricata 8.0.3 IDS (espelho SPAN passivo), encaminhando para o Splunk.
Antes de tocar em qualquer coisa, confirmei que o alvo era realmente vulnerável e que a stack de telemetria estava ativa. Também tirei um snapshot do estado pré-ataque para poder reverter quando terminasse.
Kestra executando a versão vulnerável:

O contêiner em si, ativo e acessível:

Unidades do Falco carregadas no host:

Falco emitindo eventos ativamente (modo eBPF moderno):

Serviço do Suricata ativo:

E seu eve.json gravando eventos ao vivo:

São dois erros se alinhando, não um.
Primeiro, o filtro de autenticação decide se uma requisição pode ignorar a autenticação correspondendo ao final do caminho da requisição:```java // AuthenticationFilter.java — the vulnerable check, confirmed against the self-hosted v1.3.20 source if (path.endsWith("/configs")) { // treated as a public, unauthenticated path }
Essa verificação existe para expor um único endpoint inofensivo, a configuração pública da instância. Como `endsWith` lê apenas o final da string, ele não consegue distinguir esse caminho seguro de qualquer outro caminho que por acaso termine da mesma forma.
Segundo, o roteador do Kestra ainda encaminha esses caminhos parecidos para seus handlers reais e sensíveis. `/api/v1/main/flows/configs` chega ao handler de criação de flow. `/api/v1/main/executions/configs/configs` chega ao handler de execução. O filtro libera ambos como públicos, e o roteador os executa mesmo assim. Nomeie o namespace e o ID de um flow como `configs`, e um endpoint que executa código agora termina em `/configs`, herdando assim o passe livre do caminho público.