
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, платформа оркестрации рабочих процессов с открытым исходным кодом, поставляла фильтр аутентификации, который определял, нужны ли запросу учётные данные, проверяя, заканчивается ли URL на /configs — проверка, предназначенная для открытия одной безобидной публичной конечной точки.
Поскольку проверка смотрела только на хвост строки, любой запрос, URL которого случайно заканчивался таким образом, полностью пропускал аутентификацию, включая конечные точки, которые создают и выполняют произвольный код. Результат: любой, кто может достичь уязвимого экземпляра Kestra по сети, может выполнять команды от имени root без каких-либо учётных данных, без фишинга, без подбора пароля, без необходимости в отдельном шаге повышения привилегий.
В этом упражнении этот единственный пробел был проведён от начала до конца против самостоятельно размещённого лабораторного экземпляра:
Каждый этап был зафиксирован с помощью защитной телеметрии (сетевой IDS, безопасность среды выполнения хоста, аудит Linux и системные журналы).
Влияние на бизнес при отсутствии патча: полная компрометация хоста, на котором работает Kestra, а не только приложения — и, соответственно, всего остального, что достижимо с этого хоста.
Исправление: обновитесь до Kestra 1.0.45 / 1.3.21 или более поздней версии (один только патч закрывает основную уязвимость; этапы повышения привилегий и закрепления требуют отдельного, независимого исправления — не монтируйте Docker-сокет в контейнеры приложений, см. раздел 8).
В этом отчёте документируется CVE-2026-53576 — уязвимость неаутентифицированного удалённого выполнения кода с оценкой CVSS 10.0 в Kestra ≤1.3.20, вызванная обходом аутентификации по суффиксу пути (AuthenticationFilter.java, endsWith("/configs")).
Злоумышленник, который называет пространство имён и ID рабочего процесса configs, может создавать и выполнять произвольные shell-команды без учётных данных, от имени root, внутри контейнера Kestra. Исправлено в 1.0.45 и 1.3.21. Идентичная ошибка также была независимо зарегистрирована под CVE-2026-49869 — это номер из каталога CISA KEV, связанный с реальной эксплуатацией в дикой природе. Оба следует указывать вместе, поскольку публичные источники и сканеры могут ссылаться на любой из них.
| Уязвимые | Kestra ≤ 1.3.20 (и до 1.0.45 в ветке 1.0.x) |
| Исправленные | 1.0.45 / 1.3.21+ |
| CVE | CVE-2026-53576 |
| Парный advisory | CVE-2026-49869 — та же ошибка, в каталоге CISA KEV (в дикой природе) |
| Дата | Событие |
|---|---|
| 2026-06-02 | Выпущена Kestra 1.3.21; в changelog упоминается «potential authentication bypass in the authentication filter» |
| 2026-06-03 | Выпущена Kestra 1.0.45 в ветке 1.0.x |
| 2026-09-02 | CVE-2026-49869 (парный advisory) добавлен в каталог CISA KEV |
| 2026-09-22 — 09-24 | Данное лабораторное воспроизведение, построение обнаружения и кросс-уровневая валидация |
Самостоятельно размещённый домашний стенд:
- Хост Debian (имя хоста docker, ядро 6.12.107+deb13-amd64),
- Docker Engine 29.8.1.
- Kestra развёрнута как официальный образ kestra/kestra:v1.3.20, доступна через обратный прокси Caddy по адресу kestra.int.atlasvec.com.
- Тестируемый стек телеметрии: Falco (runtime/eBPF, уровень хоста),
- Suricata 8.0.3 IDS (пассивное зеркало SPAN), пересылка в Splunk.
Прежде чем что-либо трогать, я убедился, что цель действительно уязвима, а стек телеметрии работает. Я также сделал снимок состояния до атаки, чтобы можно было откатиться после завершения.
Kestra, работающая на уязвимой версии:

Сам контейнер, запущен и доступен:

Юниты Falco, загруженные на хосте:

Falco активно генерирует события (режим modern eBPF):

Служба Suricata активна:

И её eve.json записывает события в реальном времени:

Здесь совпали две ошибки, а не одна.
Во-первых, фильтр аутентификации определяет, может ли запрос пропустить аутентификацию, сопоставляя конец пути запроса:```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 }
Эта проверка существует, чтобы открыть одну безобидную конечную точку — публичную конфигурацию экземпляра. Поскольку `endsWith` читает только хвост строки, он не может отличить один безопасный путь от любого другого пути, который случайно заканчивается так же.
Во-вторых, маршрутизатор Kestra всё равно направляет эти похожие пути к их реальным, чувствительным обработчикам. `/api/v1/main/flows/configs` достигает обработчика создания потока. `/api/v1/main/executions/configs/configs` достигает обработчика выполнения. Фильтр пропускает оба как публичные, и маршрутизатор всё равно их выполняет. Назовите namespace и ID потока `configs`, и конечная точка, выполняющая код, теперь заканчивается на `/configs`, так что она наследует бесплатный пропуск публичного пути.