// Веб

У GitLab AI Gateway критическая 9.9: когда конфиг AI-флоу превращается в шелл

cover gitlab ai gateway rce

На этой неделе GitLab закрыл 9.9 в своём AI Gateway, и это стоит большего, чем заголовок «срочно патчьтесь», потому что это чистый пример класса багов, который задаёт тон безопасности AI-агентов на годы вперёд. Если коротко: аутентифицированный пользователь с доступом к Duo Agent Platform мог написать кастомный flow, выбраться из песочницы шаблона промпта и выполнить произвольные команды на self-hosted гейтвее. Не джейлбрейкнуть модель, не вытащить промпт. Выполнить команды на хосте. CVE-2026-90970, CVSS 9.9, и не десятка она только из-за требования аутентификации.

Мы профессионально ломаем AI-агентов, так что вот часть, которую адвайзори не проговаривает: почему это повторяется, что реально контролирует атакующий, и почему гейтвей — это худшее место в стеке, где можно отдать кому-то шелл.

Что именно сломалось

AI Gateway у GitLab — это сервис, который стоит между вашим инстансом GitLab и провайдерами моделей, а Duo Agent Platform позволяет описывать кастомные «флоу», переиспользуемые AI-воркфлоу, которые вы настраиваете сами. Под капотом эти флоу рендерятся через шаблонизатор, ровно так же, как веб-фреймворк собирает страницу из шаблона и переменных. Вот и трещина.

Уязвимость классифицирована как CWE-1336, инъекция в шаблон. Если вы занимались веб-тестированием, форма вам знакома: это server-side template injection с AI-бейджиком. Движок создан, чтобы подставлять значения в строку-шаблон. В тот момент, когда атакующий может протащить синтаксис шаблона в поле, которое движок вычисляет, он поставляет уже не данные, а код, выполняющийся в контексте шаблонизатора. В большинстве движков этот контекст в одном прыжке от хоста: дотянуться до встроенного объекта, пройти по графу объектов до рантайма, и вот у вас выполнение команд. «Специально сформированная конфигурация flow» из адвайзори — это ровно оно: определение flow с директивами шаблона внутри, вычисляемое на сервере, которое выходит за пределы песочницы, в которую GitLab это завернул.

Обратите внимание, чего в этой цепочке нет: модели. Никакого хитрого промпта, никаких уговоров, никакого «игнорируй предыдущие инструкции». LLM тут сбоку. Атакующий бьёт по обвязке вокруг модели, по слою, который рендерит конфиг, а это обычный прикладной код с входной поверхностью в форме AI. Вот деталь, которую стоит усвоить, потому что вся индустрия пялится на модель и при этом тащит в прод инъектируемые шаблонизаторы позади неё.

Почему гейтвей — это худшее место, где можно проиграть

Шелл — это плохо где угодно. На этом хосте это катастрофа, и адвайзори GitLab объясняет почему в одну строчку: self-hosted гейтвей хранит ключи подписи JWT и держит соединения и с инстансом GitLab, и с внешними AI-провайдерами. Пройдёмся, что это значит для атакующего, стоящего на нём.

  • Ключи подписи JWT. Если у вас ключ, которым подписываются токены, вы не угоняете сессию, вы выпускаете токены. Любая идентичность, в любой момент, валидная по построению. Это тихий апгрейд с «RCE на одном сервисе» до «доверенный везде, что проверяет эти токены».
  • Линия в инстанс GitLab. Гейтвей — это доверенный внутренний клиент. Отсюда ваша дотягиваемость — это исходники, CI/CD, секреты, раннеры пайплайнов, обычные драгоценности короны, но подход к ним изнутри доверенного периметра, а не со страницы логина.
  • Креды провайдеров. Гейтвей аутентифицируется к внешним провайдерам моделей, так что эти ключи у него тоже есть. Это чужой компьют за ваш счёт, утечка токенов в стиле METR, и канал вывода данных, который выглядит как обычный трафик к модели.

Это смертельная позиция в любой архитектуре агентов: единственный компонент, которому доверяет всё с одной стороны и который дотягивается до всего с другой. Скомпрометируй его, и ты не внутри сервиса, ты внутри самой ткани доверия. Паттерн гейтвея — это хорошая инженерия, он централизует аутентификацию и политику, но централизованное доверие — это заодно и централизованный радиус поражения, и этот CVE — это то, как выглядит обналичивание такого радиуса.

Это паттерн, а не инцидент

Вот часть, которая должна напрягать. Это уже второй раз за год. В феврале GitLab закрыл CVE-2026-1868, тоже 9.9, тоже инъекцию в шаблон через сформированное определение flow, в тот раз это легло как отказ в обслуживании или выполнение кода. Тот же компонент, тот же класс бага, та же точка входа, с разницей в восемь месяцев. Один раз — это баг. Два раза — это поверхность.

И дело не только в GitLab. Эта форма повсюду, где в 2026 быстро выкатывали AI-фичи: конфиг, воркфлоу, «кастомная инструкция» или определение инструмента, которые пользователь пишет сам, рендерятся или вычисляются на сервере, а песочницу прикрутили сверху постфактум, вместо того чтобы спроектировать границу сразу. Песочница — это и есть маркер. Песочница нужна только вокруг того, что вы скармливаете вычислителю, а песочницы вокруг шаблонных и выражательных движков валятся с тех пор, как к ним ещё и близко не приписывали буквы A и I. AI-гейтвей унаследовал пятнадцатилетний класс веб-уязвимости и свежую, недотестированную поверхность атаки сверху.

Как вы бы это реально нашли

Если вы тестируете AI-платформу, этот CVE — это карта. Не начинайте с чат-окна, начинайте со всего, что пользователь может сконфигурировать.

  • Перечислите поверхность авторинга. Каждое место, где пользователь описывает flow, агента, кастомную инструкцию, схему инструмента, шаблон промпта, тело вебхука. Всё, что вы пишете и что платформа потом рендерит или вычисляет, — это кандидат. Этот список и есть ваша матрица тестов, и это почти никогда не та часть, которую вендор моделирует по угрозам жёстче всего.
  • Щупайте вычисление шаблона, а не поведение модели. Закидывайте классические SSTI-полиглоты в каждое конфигурируемое поле и смотрите на вычисление: арифметика, которая вернулась посчитанной, объект, который отрендерился вместо того, чтобы напечататься буквально. Если поле отражает результат выражения, а не само выражение, вы внутри движка.
  • Дальше лезьте от вычисления к выполнению. Вычисление выражений — это зацепка, а не находка. Настоящий вопрос в том, как далеко песочница пускает вас к встроенному объекту, рантайму, файловой системе, подпроцессу. Меряйте побег, а не эхо.
  • Нарисуйте, кому доверяет скомпрометированный компонент. Это шаг, который пропускают, и именно он превращает medium в 9.9. Как только у вас выполнение на гейтвее, инвентаризируйте, что он держит: ключи подписи, креды апстрима, внутренние соединения. Воздействие определяется дотягиваемостью доверия, а не самим багом.

Если у вас self-hosted гейтвей

Патчьтесь, в первую очередь и сейчас. Self-hosted GitLab AI Gateway на 18.1.6 по 19.2.3 едет на 19.2.4, ветка 19.3.x на 19.3.2, а 19.4.0 на 19.4.1. GitLab.com и Dedicated уже исправлены, это проблема self-hosted, и воркэраунда нет: патч и есть митигация. Нашёл это invisiblemeerkat через HackerOne, CISA по состоянию на 2 октября не отметила наблюдаемой эксплуатации, и вы хотите держаться впереди окна, где это изменится, потому что публичная 9.9 с понятным классом бага — это надёжный магнит для n-day работы.

Но патч этого CVE не трогает паттерн, а паттерн — это то, что достанет вас в следующий раз. Урок архитектурный: относитесь к каждому пользовательскому flow, шаблону и определению инструмента как к недоверенному коду, потому что для шаблонизатора это ровно оно и есть. Не рендерьте это в контексте, который может дотянуться до рантайма. И стройте гейтвей из предположения, что его рано или поздно скомпрометируют, чтобы когда это случится, атакующему достались короткоживущие ограниченные креды и тесный allowlist на исходящий трафик, а не ваши ключи подписи и прямая дорога к исходникам и провайдерам. Контроль перед гейтвеем, который ограничивает, до чего тот дотягивается, и записывает, что тот делал, — это разница между «мы прокрутили ключи и пошли дальше» и «мы восстанавливаем три недели того, как доверенный компонент делал всё, что ему сказали».

Искать этот класс дыр по всей реальной поверхности авторинга AI-платформы раньше, чем это сделает кто-то с конфигом flow, — это ровно то, для чего нужны аудит безопасности ИИ-агентов и тестирование MCP-серверов и цепочки инструментов.

← назад в блог