Что произошло
Уязвимость: CVE-2026-97229 — критическая уязвимость (CVSS 10.0) в том, как GitLab обрабатывает регулярные выражения в CI конфигурациях. Корень проблемы находится в Onigmo, движке регулярных выражений, встроенном в Ruby. GitLab выпустил исправленные версии 12 октября, но сам патч — это набор правок к Ruby, которые входят в официальные пакеты и образы контейнеров GitLab. Upstream Ruby выпустил исправление 23 октября в версиях Ruby 3.3.13, 3.4.12 и 4.0.9.
Атака: 20 и 21 октября новозарегистрированный аккаунт отправил специально подготовленные CI конфигурации на инстанс Alpine, который всё ещё работал на версии 19.3.4 без октябрьского патча. Это вызвало 8 сбоев рабочих процессов GitLab. В 4 случаях злоумышленник прошёл частично через эксплуатацию, но не смог выполнить следующий шаг. Атакующий также загрузил образ контейнера GitLab, что указывает на подстройку эксплуатации под конкретную сборку. Нет доказательств выполнения кода на сервере, но это исключить нельзя.
Обновление GitLab не устранило уязвимость: Обновление на GitLab 19.3.6 от 22 октября не исправило уязвимость. Патч находится не в коде GitLab, а в исправлении к Ruby, которое применяется только в официальных пакетах GitLab. На инстансе использовалась стандартная Ruby, поэтому патч не был применён.
Если запускать GitLab с собственной Ruby (из исходников или в собственном образе контейнера) вместо официальных пакетов GitLab, просто обновления недостаточно — нужна также Ruby 3.3.13, 3.4.12, 4.0.9 или позже.
Если используется образ alpinelinux/gitlab, заново загрузите alpinelinux/gitlab:19.3.6. Образ, опубликованный 27 октября, содержит Ruby 3.3.13. Любые образы 19.3.6, загруженные до 27 октября, и все более старые версии остаются уязвимыми.
Хронология инцидента
| Дата | Событие |
|---|---|
| 28 окт | Пересборка GitLab завершена; все пароли сброшены, секретные ключи GitLab заменены |
| 27 окт | GitLab закрыт для всех, кроме разработчиков и build-серверов; начата пересборка |
| 26 окт | Обнаружена уязвимость инстанса после обновления |
| 25-26 окт | Злоумышленник возвращается и пытается вернуться; попытки неудачны |
| 24 окт | Проверка aports, пакетов и релизов от 21 октября против внешних записей |
| 23 окт | Аккаунт злоумышленника заблокирован; Ruby выпускает исправление |
| 22 окт | Обновление на GitLab 19.3.6 |
| 21 окт | Основная атака; сбой GitLab, ошибки 502 и проблемы с CI-заданиями |
| 20 окт | Злоумышленник регистрирует аккаунт и начинает зондирование |
| 13 окт | Публикация CVE-2026-97229; ошибочно обновлены на GitLab 19.3.4 вместо 19.3.5 (с патчем) |
| 12 окт | GitLab выпускает исправление |
Что нам известно и что исключить нельзя
Что обнаружено
- Релизы и пакеты Alpine не модифицированы. Октябрьские стабильные релизы (3.21.9, 3.22.7, 3.23.7, 3.24.3), включая ISO-образы и тарболлы minirootfs, из которых собираются официальные образы Docker, а также все пакеты, собранные с 20 по 24 октября, поступили из коммитов aports, проверенных против записей вне GitLab. Подробнее см. FAQ ниже.
- Ключи подписи не скомпрометированы. Ключи, используемые для подписи пакетов и релизов Alpine, никогда не хранились на сервере GitLab.
- Нет доказательств выполнения кода злоумышленником: проверки времени не показали задержек, не найдены неожиданные файлы, ключи, хуки или процессы.
- Нет приватных данных, возвращённых атакующему через веб-запросы или API.
Почему нельзя быть уверенным
- Успешная эксплуатация не оставила бы сбоев и следов в логах веб-сервера.
- Часть логов дня атаки потеряна (логи фоновых заданий, файловая система старого контейнера).
- Не было логирования исходящих сетевых соединений, провайдер хостинга тоже ничего не сохраняет.
Что могло быть скомпрометировано при успешной атаке
- Электронные адреса, имена и IP-адреса всех пользователей
- Хеши паролей
- Секреты 2FA, переменные CI/CD и токены runner
- Учётные данные webhook, интеграций и push-зеркал
- Персональные токены доступа (сохранённые как хеши)
- Приватные репозитории, конфиденциальные issue и merge request
FAQ
Почему пересобирали GitLab, если удалось смягчить последствия атаки?
Поскольку нельзя исключить выполнение кода, а доказательства, нужные для его подтверждения, уже потеряны, выбрали более надёжный путь — полная пересборка инстанса. Это убирает любые следы, которые могла оставить успешная эксплуатация.
Пока GitLab закрыт, зеркала пакетов, cgit и рассылки/IRC доступны как обычно.
Затронуты ли пакеты и релизы Alpine?
Признаков компрометации в aports и релизах не найдено.
Каждый коммит в aports, добавленный с 20 по 22 октября, поступил через зафиксированный push известного разработчика. Проверено против записей, недоступных для атакующего: клона разработчика и всех 45 builder-ов. Каждый пакет, собранный с 20 по 24 октября на всех архитектурах, поступил из коммитов, опубликованных на git.alpinelinux.org. Октябрьские релизы (3.21.9, 3.22.7, 3.23.7, 3.24.3) собраны из тех же проверенных коммитов.
Проверки выполнены 24 октября, охватывая коммиты с 20 по 22 октября и пакеты до 24 октября. GitLab оставался уязвимым до закрытия 27 октября, поэтому расширяем проверки до этой даты.
Затронут ли пакет Ruby в Alpine?
Баг находится в движке регулярных выражений Ruby, поэтому уязвимы любые программы, компилирующие регулярные выражения из недоверенного источника, не только GitLab. Alpine 3.22, 3.23, 3.24 и edge поставляются с Ruby 3.4.12, а Alpine 3.21 — с Ruby 3.3.13; обе версии включают исправление. Запустите apk upgrade для обновления.
Какие изменения планируются в ответ на этот инцидент?
- Исправленный Ruby: пересобранный инстанс работает на Ruby с патчем (3.3.13 или позже).
- Более быстрое патчирование: применять критические безопасности GitLab в течение дня, проверять каждый релиз на патчи к Ruby и другим компонентам, которые нужно применить в собственной сборке.
- Лучшее логирование: записывать исходящие соединения из хоста GitLab и подключения БД, хранить логи дольше 14 дней.
- Подписанные теги релизов, чтобы релизы можно было проверить независимо от GitLab.