
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, une plateforme open-source d'orchestration de workflows, a livré un filtre d'authentification qui décidait si une requête nécessitait des identifiants en vérifiant si l'URL se terminait par /configs - une vérification destinée à exposer un seul endpoint public inoffensif.
Parce que la vérification ne portait que sur la fin de la chaîne, toute requête dont l'URL se terminait de cette manière contournait entièrement l'authentification, y compris les endpoints qui créent et exécutent du code arbitraire. Le résultat : quiconque peut atteindre une instance Kestra vulnérable sur le réseau peut exécuter des commandes en tant que root sans aucun identifiant, sans hameçonnage, sans devinette de mot de passe, sans étape d'élévation de privilèges requise.
Dans cet exercice, cette unique faille a été exploitée de bout en bout contre une instance de laboratoire auto-hébergée :
Chaque étape a été capturée face à la télémétrie défensive (IDS réseau, sécurité d'exécution hôte, audit Linux et journaux système).
Impact métier si non corrigé : compromission complète de l'hôte exécutant Kestra, pas seulement de l'application - et par extension de tout ce qui est accessible depuis cet hôte.
Correctif : mettre à niveau vers Kestra 1.0.45 / 1.3.21 ou ultérieur (le correctif seul ferme la vulnérabilité principale ; les étapes d'élévation et de persistance nécessitent un correctif distinct et indépendant - ne montez pas le socket Docker dans les conteneurs applicatifs, voir Section 8).
Ce rapport documente CVE-2026-53576, une vulnérabilité d'exécution de code à distance non authentifiée de score CVSS 10.0 dans Kestra ≤1.3.20, causée par un contournement d'authentification par suffixe de chemin (AuthenticationFilter.java, endsWith("/configs")).
Un attaquant qui nomme le namespace et l'ID d'un workflow configs peut créer et exécuter des commandes shell arbitraires sans identifiants, en tant que root, à l'intérieur du conteneur Kestra. Corrigé dans 1.0.45 et 1.3.21. Le même bug a également été signalé indépendamment sous CVE-2026-49869, qui est le numéro listé dans le catalogue KEV de la CISA lié à une exploitation réelle en conditions opérationnelles. Les deux doivent être cités ensemble, car les sources publiques et les scanners peuvent référencer l'un ou l'autre.
| Vulnérable | Kestra ≤ 1.3.20 (et pré-1.0.45 sur la branche 1.0.x) |
| Corrigée | 1.0.45 / 1.3.21+ |
| CVE | CVE-2026-53576 |
| Avis jumeau | CVE-2026-49869 - même bug, listé dans le KEV de la CISA (en conditions opérationnelles) |
| Date | Événement |
|---|---|
| 2026-06-02 | Publication de Kestra 1.3.21 ; le changelog mentionne un « contournement d'authentification potentiel dans le filtre d'authentification » |
| 2026-06-03 | Publication de Kestra 1.0.45 sur la branche 1.0.x |
| 2026-09-02 | CVE-2026-49869 (l'avis jumeau) ajouté au catalogue KEV de la CISA |
| 2026-09-22 au 09-24 | Reproduction en laboratoire, construction de la détection et validation multicouche |
Homelab auto-hébergé :
- Hôte Debian (nom d'hôte docker, noyau 6.12.107+deb13-amd64),
- Docker Engine 29.8.1.
- Kestra déployé via l'image officielle kestra/kestra:v1.3.20, accessible via un reverse proxy Caddy à kestra.int.atlasvec.com.
- Pile de télémétrie testée : Falco (runtime/eBPF, niveau hôte),
- Suricata 8.0.3 IDS (miroir SPAN passif), redirigeant vers Splunk.
Avant de toucher quoi que ce soit, j'ai confirmé que la cible était réellement vulnérable et que la pile de télémétrie était active. J'ai également pris un instantané de l'état pré-attaque afin de pouvoir revenir en arrière une fois terminé.
Kestra exécutant la version vulnérable :

Le conteneur lui-même, démarré et accessible :

Les unités de Falco chargées sur l'hôte :

Falco émettant activement des événements (mode eBPF moderne) :

Le service Suricata actif :

Et son eve.json écrivant des événements en direct :

Il s'agit de deux erreurs qui s'alignent, pas d'une seule.
Premièrement, le filtre d'authentification décide si une requête peut contourner l'authentification en faisant correspondre la fin du chemin de la requête :```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 }
Ce contrôle existe pour exposer un seul endpoint inoffensif, la configuration de l'instance publique. Comme `endsWith` ne lit que la fin de la chaîne, il ne peut pas distinguer ce chemin sûr de tout autre chemin qui se termine de la même manière.