
Reprodução ponta a ponta e detecção em múltiplas camadas da CVE-2026-53576, a RCE não autenticada no Kestra — levada além do PoC básico para mostrar como uma configuração incorreta comum do socket do Docker transforma o root do contêiner em comprometimento total do host.
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 |
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.
O par de requisições capturado mostra isso claramente. `GET /api/v1/main/flows/search` sem credenciais retorna `401`. `POST /api/v1/main/flows/configs` com o mesmo cabeçalho de autenticação vazio retorna `200` e armazena o flow (ver §5.1).
## 5. Simulação de Ataque
> Cada passo abaixo é capturado com sua própria captura de tela. Tudo isso roda dentro do meu próprio homelab isolado contra uma instância Kestra auto-hospedada atrás do proxy reverso.
### 5.1 Estágio 1 - bypass de autenticação -> root dentro do contêiner Kestra
**Controle :** `GET /api/v1/main/flows/search` sem credenciais → `401 Unauthorized`.
Confirma que a autenticação é aplicada em uma rota normal.

_____
**Plantar :** Enviando `POST /api/v1/main/flows/configs` sem cabeçalho de autenticação. O corpo é um YAML de flow cujo `namespace` e `flow id` são ambos `configs`, contendo uma tarefa Commands que usa o task runner Process. O servidor retorna `200 OK` e armazena o flow. O sufixo `/configs` em uma rota de outra forma protegida é o que dispara o bypass **(ver Seção 4).**

**Escutar e Aguardar** : Iniciando um listener simples usando nc para fins de teste, para capturarmos a reverse shell.

**Disparo / Execução** `POST /api/v1/main/executions/configs/configs`, sem cabeçalho de autenticação → `200 OK`, nova execução criada.

**BaaaaM :** Conseguimos a shell, mas lembre-se - estamos "isolados", `root` **MAS** dentro do contêiner Docker do Kestra, então "não deveríamos" conseguir escapar daqui. "**bem, foi o que eu pensei**"

O comando da tarefa roda como filho direto do processo JVM do Kestra, confirmado pela árvore de processos do lado do host, e completa com sucesso conforme o próprio log de execução do Kestra.
**Dashboard de Logs do Kestra**

**Árvore de Processos do Kestra**

**Resultado:** execução remota de código não autenticada como root, dentro do contêiner Kestra. Esta é a prova completa e autocontida do **CVE-2026-53576**.
### 5.2 Estágio 2 - escalação via socket Docker exposto (específico do homelab, não faz parte do próprio CVE)
A partir da shell do Estágio 1, `/var/run/docker.sock` foi encontrado montado no contêiner - um padrão Docker-outside-of-Docker (DooD), comum quando o próprio task runner `Docker` do Kestra está configurado, já que ele precisa de um daemon para se comunicar.
Alcançar esse socket de qualquer forma é equivalente a **root** no host: a API do Docker permite que um cliente configure montagens de bind arbitrárias do host e namespaces de PID/rede do host para contêineres que ele cria, e o daemon por trás do socket já roda como root no host.
Isso não é um exploit de kernel ou de escape de contêiner - é a API do Docker fazendo o que foi projetada para fazer, alcançada de um lugar de onde não deveria ter sido alcançável.
Usando o socket, criei um contêiner irmão com o sistema de arquivos do host montado e namespaces de PID e rede do host, e então o iniciei.
**Nota:** uma segunda variante, mais silenciosa, também surgiu durante os testes, embora eu não a tenha capturado separadamente. Em vez de sempre criar um novo contêiner irmão, o mesmo acesso ao socket permite executar `POST /containers/{id}/exec` contra um contêiner que já está em execução, de modo que não há nenhum evento de criação de contêiner. Neste host Docker eu tenho tanto o Kestra quanto o Portainer, qualquer um dos quais eu poderia usar para o mesmo escape. Isso importa para detecção: qualquer regra focada na criação de um novo contêiner privilegiado perde essa variante.
Confirmando root e encontrando o socket ali, sem nenhuma restrição de montagem:

Verificando se o daemon do Docker é realmente alcançável através do socket:

Listando quais imagens já estão locais, para que eu não precise baixar nada:

Primeira tentativa: um contêiner privilegiado com o sistema de arquivos do host montado:

Segunda tentativa, desta vez adicionando namespaces de PID e rede do host:

Terceira tentativa, fazendo chroot diretamente no sistema de arquivos do host montado:

Listener ativo e aguardando na porta para a qual a shell de escape fará o callback:

Iniciando o contêiner:

**Root, mas desta vez é o host, não o contêiner:**

Versão do kernel correspondendo ao host real, não à visão isolada de um contêiner:

Atualizando para uma shell interativa adequada para o resto da sessão:

### 5.3 Estágio 3 - persistência, disparo confirmado
A partir da shell de root no host, configurei dois mecanismos de persistência independentes,
**Primeiro**, uma chave SSH. Verifiquei quem já tinha acesso :

Depois verifiquei a própria configuração do sshd em busca de qualquer coisa que bloqueasse uma nova chave:

Gerei um par de chaves na máquina atacante:

Confirmei que o sshd estava realmente escutando:

Coloquei a chave pública no `authorized_keys` do root:

E fiz login com a chave privada correspondente:

**PS:** Esse é um acesso root independente da cadeia de RCE original. Mesmo que o Kestra seja corrigido, essa chave ainda funciona.
**Segundo**, um beacon via cron. Coloquei um callback em nível de root configurado para rodar em um intervalo, depois testei com um listener novo para ver se ele realmente disparava conforme o agendamento:

**Disparou. Um segundo ponto de apoio no host, independente tanto do RCE quanto da chave SSH.**
### 5.4 Linha do tempo da kill-chain verificada.
A linha do tempo abaixo é diferente: ela é reconstruída inteiramente a partir de telemetria independente do lado do defensor (IDS de rede + segurança de runtime do host), extraída e validada ao vivo contra dados reais do Splunk.
**RCE primário - a rede detecta a entrega, o host confirma a execução, 103 segundos de diferença:**
| Hora (EDT) | Camada | Evento |
| ------------ | ------------------ | -------------------------------------------------------------------------------------------- |
| 02:46:09.778 | Rede (Suricata) | Assinatura pública ET para este CVE exato dispara |
| 02:47:52.277 | Host (Falco) | Reverse shell confirmada dentro do contêiner Kestra, comando exato e ID do contêiner capturados |
**Escalação - rede e host corroboram independentemente partes diferentes do mesmo evento:**
| Hora (EDT) | Camada | Evento |
| ------------ | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| 03:48:55.503 | Host (Falco) | Reverse shell a partir do contêiner de escalação |
| 03:51:57.360 | Rede (Suricata) | Fluxo TCP **e** um alerta baseado em conteúdo - a string literal `uid=0(root)` foi vista saindo do host em texto claro quando `id` foi executado |
## 6. Engenharia de Detecção
Construí as detecções contra telemetria real capturada, depois testei cada uma contra uma reprodução. A matriz mostra onde havia cobertura antes de eu começar e onde não havia.
### 6.0 Matriz de cobertura de detecção
| Estágio | Rede (Suricata) | Host (Falco) | Host (auditd/journald) | Status |
| --- | --- | --- | --- | --- |
| Requisição de exploit inicial | Assinatura pública ET dispara | Sem visibilidade de camada de aplicação | - | Coberto (pré-existente) |
| Execução de RCE | - | Regra nativa, marcada com T1059 | - | Coberto (pré-existente) |
| Escalação via socket Docker (a técnica) | - | Lacuna: captura apenas a shell resultante, não as chamadas de API de abuso do socket | Registros EXECVE capturam as chamadas exatas de `curl --unix-socket` | Lacuna encontrada, fechada com auditd + uma regra Falco personalizada |
| Confirmação do impacto da escalação | Alerta de conteúdo sobre a saída de `id` vazada | Mesma regra genérica de shell | - | Coberto (pré-existente, entre camadas) |
| Persistência via SSH | - | - | journald: ciclo de vida completo do PAM mais fingerprint da chave | Coberto (somente host) |
| Persistência via cron | - | - | journald e linux_audit, duas fontes, cadência exata de 5 min | Coberto (somente host) |
A lacuna é a escalação via socket Docker. As regras padrão do Falco capturam a shell que um contêiner comprometido gera, mas nada no conjunto padrão estável sinaliza um processo alcançando `/var/run/docker.sock` para acionar a API do Docker diretamente. As regras que tocariam em lançamentos de contêineres privilegiados, `Launch Privileged Container` e `Launch Sensitive Mount Container`, são entregues com maturidade `incubating` e `sandbox`, então o conjunto de regras padrão também não as carrega. Fechei a lacuna com uma busca de correlação do auditd (Detecção 03) e uma regra Falco personalizada (§6.3).
### 6.1 Splunk - cinco buscas de correlação, implantadas e agendadas
Todas as cinco rodam ao vivo no Splunk (`*/5 * * * *`, rastreamento de alertas habilitado, throttling por campo), não apenas escritas e deixadas como texto. O SPL completo, notas exatas de FP, severidade, tags MITRE e runbooks de resposta para cada uma estão em `detections/splunk/*.spl`. A tabela de status abaixo é o resultado testado ao vivo para cada uma, incluindo um bug real que encontrei e corrigi.
| # | Detecção | MITRE | Status |
| --- | ---------------------------------------------------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| 01 | Assinatura de exploit de rede (consome o alerta Suricata ET) | T1190 | **Disparou** - reprodução histórica confirmada, sem novos eventos desde então (fora do lookback atual) |
| 02 | Execução de RCE no host (regra Falco de redirecionamento para rede) | T1059 | **Disparou** - reprodução histórica confirmada |
| 03 | Abuso de socket Docker (auditd, o fechador de lacuna) | T1610, T1611 | **Disparou no próprio agendador ao vivo** - `triggered_alert_count: 1` confirmado na execução real de `*/5 * * * *`, não apenas em um teste manual |
| 04 | Persistência de login root via SSH | T1098.004, T1021.004 | **Disparou** - reprodução histórica confirmada |
| 05 | Persistência via beacon cron | T1053.003 | **Implantada com um bug que encontrei e corrigi ao vivo.** A janela de despacho de `-10m` continha apenas dois dos três buckets de 5 minutos que o limiar `distinct_intervals >= 3` precisa, então ela nunca poderia disparar apesar de o beacon ainda estar rodando nos dados reais. Ampliei para `-30m` e reimplantei - e o agendador a disparou 53 vezes desde então, então a correção se sustenta. |
A divisão de trabalho da Detecção 03 é deliberada: em vez de reimplementar a própria lógica de assinatura do Suricata em SPL, ou tentar fazer o Falco capturar uma técnica em nível de socket para a qual ele não foi construído, a camada de SIEM aqui consome o registro EXECVE do auditd das chamadas exatas de `curl --unix-socket` - a fonte de telemetria comprovadamente mais confiável para essa técnica específica.
1. **Detecção 01** - assinatura ET disparando (alerta `suricata:eve`):```spl
index=main sourcetype=suricata:eve event_type=alert
alert.signature="ET WEB_SPECIFIC_APPS Kestra Unauthenticated Remote Code Execution (CVE-2026-53576)"
| stats count min(_time) as first_seen max(_time) as last_seen
values(src_ip) as source_ips
by dest_ip dest_port
| eval first_seen=strftime(first_seen,"%Y-%m-%d %H:%M:%S")
| eval last_seen=strftime(last_seen,"%Y-%m-%d %H:%M:%S")

Detecção 02 - a regra de redirecionamento para a rede do Falco, detalhada por contentor. O IP de origem muda do endereço de bridge do contentor Kestra (172.17.0.3, RCE primário na porta 4489) para o próprio host (172.66.66.67, escalonamento na porta 4491) - a escalada de contentor para host tornada visível - enquanto o destino permanece constante: o listener do atacante em 172.66.66.125:

Detecção 03 - registos EXECVE do auditd de curl --unix-socket docker.sock:

Detecção 04 - início de sessão SSH root no journald, impressão digital da chave capturada:

Detecção 05 - o beacon cron de ficheiro oculto com ponto (/usr/local/bin/.sysmon) a correr como root numa cadência exata de 5 minutos: 79 intervalos distintos ao longo de ~6,5 horas (04:30-11:00 EDT). O limiar distinct_intervals >= 3 é o que separa um beacon periódico de um trabalho cron pontual:

Todas as cinco implementadas como pesquisas guardadas agendadas (*/5 * * * *):

Prova de que o agendador cron realmente as executa, não apenas que existem: todas as cinco foram executadas 54 vezes. A Detecção 03 disparou uma vez (o abuso do docker-socket, 06:35 EDT) e a Detecção 05 disparou 53 vezes (o beacon cron ainda ativo). As Detecções 01/02/04 mostram 0 disparos, pois são eventos históricos pontuais (pedido de exploit, RCE, início de sessão SSH) que já saíram da janela de retrospetiva -10m, enquanto uma instância ativa ou recorrente ainda alertaria:

O padrão de reverse-shell /dev/tcp/ - usado tanto no RCE primário como no callback de escalonamento. O SigmaHQ disponibiliza uma regra para isso: "Suspicious Reverse Shell Command Line" (id 738d9bcf-6999-4fdb-b4ac-3033037db8ab, por Florian Roth na Nextron Systems), e uma das suas palavras-chave é bash -i >& /dev/tcp/ - exatamente o que apareceu na nossa captura.
Então puxei essa regra sem alterações (detections/sigma/lnx_shell_susp_rev_shells.yml) e verifiquei a sua palavra-chave contra o mesmo evento Falco que a Detecção 02 já capturou. O Sigma não "dispara" por si só - é uma assinatura portátil, não um motor em execução - mas posso mostrar a sua palavra-chave a incidir sobre telemetria real desta execução em vez de um exemplo de manual.
Regra pública do SigmaHQ "Suspicious Reverse Shell Command Line" - a sua palavra-chave bash -i >& /dev/tcp/ contra o mesmo evento real da Detecção 02:

detections/falco/docker_socket_abuse.yaml - implementada na instância Falco em execução e confirmada a disparar numa reprodução real, 2026-09-24T10:27:29Z.
O conjunto de regras predefinido do Falco não cobre isto. Detetar um processo a aceder a /var/run/docker.sock não é uma ideia nova - os próprios exemplos Falco da Sysdig fazem-no ao vigiar open_write no caminho do socket - mas não existe tal regra no conjunto fornecido/predefinido (o projeto tem um pedido aberto para uma, falcosecurity/falco #2940), e a única regra predefinida adjacente só apanha os CLIs docker/kubectl, não um curl --unix-socket em bruto.
O senão: essa abordagem padrão de open_write-no-socket não disparou nesta configuração - com modern_bpf e um espelho passivo, o socket é alcançado via connect(), não open(). Por isso, faço a correspondência na linha de comando do processo no momento do spawn (spawned_process + proc.cmdline contains "docker.sock"), a mesma classe de eventos que o Falco já trata de forma fiável aqui. Dispara duas vezes por chamada - o wrapper de shell e a folha curl - com contexto completo:```
priority=Critical, container_id=d417e027d444, image=kestra/kestra:v1.3.20, user=root, cmdline="curl -s --unix-socket /var/run/docker.sock http://localhost/version", tags=[T1610, T1611]
Regra Falco personalizada disparando - "Unexpected Process Accessing Docker Socket" (T1610/T1611):

Regras Falco padrão que dispararam - o conjunto padrão não tem regra para docker-socket, que é a lacuna:

### 6.4 Suricata - cobertura pública existente, regra personalizada adiada
A camada de rede para o exploit principal já está coberta por uma assinatura pública do Emerging Threats, `ET WEB_SPECIFIC_APPS Kestra Unauthenticated Remote Code Execution (CVE-2026-53576)`, que disparou em tráfego real durante a Fase 2.
Abaixo está o mesmo bypass visto na camada de rede, e construí a consulta a partir do padrão da vulnerabilidade. Toda requisição cujo caminho termina em `/configs` em um endpoint `flows` ou `executions` retornou `200`, enquanto uma rota normal (`/flows/search`) retornou o esperado `401`.
A coluna `Attacker IP (XFF)` é a origem HTTP real, lida do cabeçalho `X-Forwarded-For`: `10.10.10.106`, meu Mac rodando Burp. O próprio `src_ip` do Suricata só vê o salto do proxy reverso (`172.66.66.1`). Essa é uma máquina diferente da box Kali `172.66.66.125` que depois recebeu os reverse shells e fez o login SSH, então o exploit HTTP e os callbacks vieram de hosts separados.

### 6.5 Dashboard
`cve_2026_53576_kill_chain` está implantado no Splunk e contém: KPIs de destaque (camadas de detecção, técnicas ATT&CK, detecções implantadas, mecanismos de persistência), um gráfico de colunas da linha do tempo do ataque colorido por camada de telemetria, um mapa da kill chain do MITRE ATT&CK com uma contagem de evidências ao vivo por estágio, a linha do tempo correlacionada de rede e host da §5.4, cobertura de detecção por saved search agendada, o detalhamento da técnica de docker-socket, e uma tabela de indicadores de comprometimento extraída ao vivo dos logs.
- KPIs, o gráfico da linha do tempo do ataque, e o início do mapa ATT&CK:

- O restante do mapa ATT&CK, a kill chain correlacionada, a cobertura de detecção ao lado do detalhamento de docker-socket, e a tabela de IOC:

## 7. Mapeamento ATT&CK
| Tática | Técnica | Evidência |
| -------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| Initial Access | T1190 - Exploit Public-Facing Application | Requisições control/plant/execute (§5.1); disparo da assinatura ET do Suricata, §5.4 |
| Execution | T1059.004 - Command and Scripting Interpreter: Unix Shell | Tarefa `Commands` do Kestra, árvore de processos do host (`07-kestra-process-tree.png`); regra Falco, §6.1 Detecção 02 |
| Command and Control | T1095 - Non-Application Layer Protocol | Reverse shell TCP bruto via `/dev/tcp/` - nenhum enquadramento C2 de camada de aplicação usado |
| Discovery | T1613 - Container and Resource Discovery | Enumeração de imagens Docker via o socket (`10-docker-images-enum.png`) |
| Privilege Escalation | T1610 - Deploy Container | Criação/inicialização de container irmão via a API do Docker (`11`–`15`); registros EXECVE do auditd, §6.1 Detecção 03 |
| Privilege Escalation | T1611 - Escape to Host | Confirmação de root no host, correspondência de hostname/kernel (`16`, `17`) |
| Persistence | T1098.004 - Account Manipulation: SSH Authorized Keys | Implantação de chave em `/root/.ssh/authorized_keys` (`23`) |
| Lateral Movement | T1021.004 - Remote Services: SSH | Login root bem-sucedido baseado em chave (`24`); journald, §6.1 Detecção 04 |
| Persistence | T1053.003 - Scheduled Task/Job: Cron | Beacon de cron, confirmado disparando conforme agendado (`25`); §6.1 Detecção 05 |
## 8. Remediação & Hardening
**Correção primária.** Atualize para Kestra 1.0.45 (linha 1.0.x) ou 1.3.21+ (linha 1.3.x). Isso por si só fecha o auth-bypass - o Estágio 1 deste exercício - e é
a única correção que não requer controles compensatórios adicionais uma vez aplicada. Veja [GHSA-2q47-568g-9h4f](https://github.com/kestra-io/kestra/security/advisories/GHSA-2q47-568g-9h4f).
**Se a aplicação imediata do patch não for possível**, controles compensatórios, em ordem de impacto:
1. **Aplicação no proxy reverso** - como o filtro vulnerável só falha no sufixo do caminho bruto, um proxy reverso na frente do Kestra (Caddy, neste lab) pode aplicar independentemente autenticação em qualquer caminho que corresponda a `/api/v1/*/(flows|executions)/.*` independentemente de como ele termina, fechando o bypass em uma camada que o bug da aplicação não alcança.
2. **Restringir o mount do socket do Docker** - isso fecha os Estágios 2–3 inteiramente, independente do patch do Kestra. Não faça bind-mount de `/var/run/docker.sock` no container do Kestra. Se o executor de tarefas `Docker` for genuinamente necessário, use um proxy de socket com escopo (por exemplo, `docker-socket-proxy`) que faça allowlist de chamadas específicas da API em vez de conceder acesso total ao daemon - acesso total ao socket é equivalente a root no host, como demonstrado na §5.2.
3. **Hardening de SSH** - o primeiro mecanismo da cadeia de persistência dependia de o root ser alcançável via SSH baseado em chave. `PermitRootLogin no` (ou exigir um bastion/MFA para root) teria bloqueado esse caminho específico de persistência independentemente do RCE inicial - vale a pena fazer independente deste CVE.
4. **Cobertura de detecção interina** - as buscas de correlação do Splunk e a regra Falco personalizada, todas implantadas e verificadas durante este exercício, fornecem a cobertura interina para os estágios desta cadeia específica enquanto o patch está agendado.
**Higiene pós-incidente**, se este padrão for encontrado já explorado: trate como comprometimento total do host, não apenas comprometimento da aplicação - rotacione toda credencial e segredo aos quais a instância do Kestra tinha acesso (entradas do KV store, credenciais de conexão para sistemas downstream), não apenas o próprio acesso do Kestra.
**Status in-the-wild.** `CVE-2026-49869`, o advisory gêmeo para este mesmo bug, está listado no catálogo KEV da CISA e ligado a campanhas observadas de crypto-mining e roubo de credenciais de nuvem. `CVE-2026-53576` (este relatório) não tem listagem KEV própria, mas é a mesma vulnerabilidade. Ferramentas de gestão de vulnerabilidades que rastreiam apenas um dos dois números de CVE podem subnotificar a exposição.
## 9. Referências
- Kestra Security Advisory - [GHSA-2q47-568g-9h4f](https://github.com/kestra-io/kestra/security/advisories/GHSA-2q47-568g-9h4f) (CVE-2026-53576, fonte primária deste relatório)
- Advisory gêmeo - [GHSA-5vc5-wxxq-3fjx](https://github.com/kestra-io/kestra/security/advisories/GHSA-5vc5-wxxq-3fjx) (CVE-2026-49869, bug idêntico, listado no KEV da CISA)
- CVE.org - [CVE-2026-53576](https://www.cve.org/CVERecord?id=CVE-2026-53576), [CVE-2026-49869](https://www.cve.org/CVERecord?id=CVE-2026-49869)
- CISA Known Exploited Vulnerabilities Catalog - https://www.cisa.gov/known-exploited-vulnerabilities-catalog (entrada CVE-2026-49869, adicionada em 2026-09-02)
- Releases corrigidas, ambas confirmadas como existentes e tagueadas - [v1.3.21](https://github.com/kestra-io/kestra/releases/tag/v1.3.21) (2026-06-02, changelog referencia explicitamente "potential authentication bypass in the authentication filter"), [v1.0.45](https://github.com/kestra-io/kestra/releases/tag/v1.0.45) (2026-06-03)
- Técnica de escalação via socket do Docker (§5.2) - [HackTricks: Docker Breakout / Privilege Escalation](https://hacktricks.wiki/en/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation/index.html), [Trail of Bits: Understanding Docker Container Escapes](https://blog.trailofbits.com/2019/07/19/understanding-docker-container-escapes/), [MindPatch: Docker Escape](https://www.mindpatch.net/posts/docker-escape/)
- Regra Sigma (§6.2) - a regra pública que usei em vez de escrever a minha própria: [SigmaHQ "Suspicious Reverse Shell Command Line"](https://github.com/SigmaHQ/sigma/blob/master/rules/linux/builtin/lnx_shell_susp_rev_shells.yml) (id `738d9bcf-6999-4fdb-b4ac-3033037db8ab`, Florian Roth / Nextron Systems), usada sob a [Detection Rule License 1.1](https://github.com/SigmaHQ/sigma/blob/master/LICENSE.Detection.Rules.md)
- Regra Falco (§6.3) - a lacuna do docker-socket é uma solicitação aberta upstream ([falcosecurity/falco #2940](https://github.com/falcosecurity/falco/issues/2940)); a regra personalizada segue o padrão em [Sysdig's Docker + Falco examples](https://www.sysdig.com/blog/docker-falco-security)
| Esta reprodução em laboratório, construção de detecção e validação entre camadas |