Изолированная среда, в которой TeamCity выполняет конфигурации сборок, не удерживает код внутри себя. Обход этой защиты позволяет запустить произвольный код на сервере непрерывной интеграции, а такой сервер хранит учётные данные, ключи подписи и доступ к репозиториям компании. Вторая уязвимость в том же продукте открывает чтение локальных репозиториев через подмодули Git. JetBrains закрыла обе проблемы и подготовила исправленные сборки. Ни одну из них не назвали критической, верхняя оценка - высокая.
Детали уязвимостей
Идентификаторы - CVE-2026-106218 и CVE-2026-106219. Первую производитель оценил как уязвимость высокой степени опасности, вторую - как среднюю. Побег из песочницы нашёл исследователь Joakim Bulow, ошибку в обработке подмодулей - Than Kien. Обе проблемы касаются серверов TeamCity, развёрнутых на своих мощностях; облачную версию обновляет сам производитель, и её пользователям делать ничего не нужно.
Kotlin DSL - это способ описать сборку кодом на языке Kotlin вместо заполнения форм в веб-интерфейсе. Подход удобный: конфигурацию можно хранить в репозитории, проверять при изменениях и переиспользовать между проектами. Однако исполняемый код требует ограничений, поэтому TeamCity запускает его в песочнице - изолированной среде с урезанными правами. Фильтры, которые отсекают опасные конструкции языка, оказались неполными. Ошибку отнесли к классу CWE-184, то есть к неполному списку запрещённого: часть операций разработчики просто не предусмотрели.
Обход подбирается прямо в настройках сборки. Как только это удаётся, код покидает изолированную среду и исполняется с правами сервера. С этого момента злоумышленник получает то же, что и администратор TeamCity: переменные окружения, где обычно лежат токены, хранилище артефактов и подключения к системам развёртывания. Песочница нужна именно для того, чтобы право редактировать сборки не превращалось в полный контроль над сервером. Здесь эта защита не срабатывает. Через сервер сборки удобно протащить чужой код прямо в релиз: изменить шаг сборки, подменить артефакт, дотянуться до продакшена.
Вторая уязвимость скромнее по последствиям, зато интереснее по вектору. Подмодуль Git - вложенный репозиторий, который основная сборка подключает к себе. TeamCity адрес такого подмодуля не проверяла. Подставив свой адрес, атакующий заставлял сервер обратиться к локальным репозиториям на собственной файловой системе. Класс ошибки - CWE-73, отсутствие проверки внешнего пути. Сервер раскрывает исходный код проектов, которые на нём размещены, а для компаний с закрытыми продуктами это утечка интеллектуальной собственности.
Обе уязвимости требуют, чтобы у атакующего уже был доступ к настройкам сборок. Это сужает круг риска, но не отменяет его. Права на редактирование конфигураций в крупных командах выдают десяткам разработчиков, а иногда и подрядчикам. Значит, один скомпрометированный аккаунт или один невнимательный сотрудник превращает обычную учётную запись в точку входа на сервер, откуда видны все связанные проекты. Сервер непрерывной интеграции хранит ключи сразу от многих систем, поэтому каждая ошибка изоляции обходится дороже, чем на рядовом рабочем узле.
Сведений об эксплуатации этих уязвимостей в реальных атаках производитель не приводил. Исследователи участвовали в программах раскрытия и получили вознаграждение - обычная для JetBrains практика. Публикация подробностей одновременно с патчами снижает вероятность того, что обход уже применяли втайне, хотя полностью её не исключает. Проверить свою версию можно в веб-интерфейсе TeamCity, в разделе сведений о сервере.
Исправления разошлись по разным веткам. Побег из песочницы Kotlin DSL закрывают сборки 2026.1.3 и 2025.11.7, ошибку с подмодулями - версия 2026.2.1. Тем, кто обновляется редко, разумнее сразу перейти на последнюю доступную сборку: она включает обе правки. Обходных настроек, которые снимали бы риск без установки новой версии, производитель не предложил. После обновления проверьте, не появились ли в проектах посторонние конфигурации и не менялись ли адреса подмодулей. Если такие следы есть, токены из переменных окружения придётся сменить, а подключения к системам развёртывания - пересмотреть.
Изоляция в инструментах сборки оказывается слабее, чем предполагают разработчики. Отчасти потому, что язык конфигураций богаче, чем кажется: чем больше в нём возможностей, тем длиннее список конструкций, которые нужно фильтровать. История с подмодулями напоминает о другом. Удобная функция для работы с вложенными репозиториями легко превращается в канал доступа к локальным данным, если разработчики не проверяют то, что приходит извне. Для служб, которые собирают и развёртывают чужой код, такая проверка - базовая гигиена, а не дополнительная настройка.
Ссылки