На этой неделе команда поддержки Composer, менеджера пакетов для PHP, выпустила экстренные исправления для критической уязвимости. Проблема, получившая идентификатор GHSA‑f9f8‑rm49‑7jv2, приводит к утечке встроенных токенов аутентификации GitHub (GITHUB_TOKEN) в журналы задач непрерывной интеграции (CI). Каждый PHP-проект, использующий устаревшую версию Composer в пайплайне CI, оказывается под угрозой. Исправления доступны в версиях 2.9.8, 2.2.28 (LTS) и 1.10.28 (устаревшая ветка).
Детали уязвимости
Суть уязвимости кроется в механизме проверки OAuth-токенов GitHub. Разработчики Composer в 2021 году добавили регулярное выражение, которое разрешает только символы из набора [.A-Za-z0-9_]. Такое ограничение было оправдано: на тот момент все токены GitHub соответствовали этому формату. Однако позднее GitHub представил новый структурированный формат для внутренних токенов GitHub Actions: ghs_<идентификатор>_<JWT>. JWT (JSON Web Token, токен в формате JSON) кодируется с помощью base64url, где вместо символов "+" и "/" используются дефис и подчёркивание. Новый формат содержит дефисы, которые и вызывают ошибку валидации.
Когда Composer не может проверить токен, он вставляет его полное значение прямо в сообщение исключения. Вот как выглядит уязвимый код:
| 1 2 3 4 5 | if (!Preg::isMatch('{^[.A-Za-z0-9_]+$}', $token)) { throw new \UnexpectedValueException( 'Your github oauth token for '.$domain.' contains invalid characters: "'.$token.'"' ); } |
Это исключение затем перехватывается библиотекой Symfony Console, которая выводит его в стандартный поток ошибок (stderr). В среде CI весь вывод stderr автоматически попадает в журнал задачи. Таким образом, токен оказывается в логах.
Особую опасность ситуации придаёт то, что многие популярные действия GitHub (actions), например shivammathur/setup-php, автоматически регистрируют GITHUB_TOKEN в глобальном файле auth.json Composer. Для активации утечки пользователю не нужно предпринимать никаких дополнительных действий - достаточно запустить Composer в рамках CI.
На первый взгляд, GitHub должен маскировать секреты в логах, заменяя их на звёздочки. Однако в данном случае механизм маскировки не срабатывает. Библиотека Symfony Console обрамляет вывод исключения ANSI-кодами управления цветом и может переносить длинные строки по ширине терминала. Из‑за этого токен никогда не появляется в логе единым непрерывным фрагментом. Секрет-маскер ищет точное совпадение подстроки, поэтому он либо вообще не находит токен, либо маскирует лишь небольшую часть, оставляя остальное видимым. В результате в сохранённых журналах можно увидеть частично скрытый токен, а рядом - его полную версию в сыром виде.
Какие токены под угрозой? Это зависит от прав доступа, установленных для GITHUB_TOKEN в репозитории. В феврале 2023 года GitHub изменил стандартные настройки для новых организаций и личных аккаунтов, сделав токены read-only по умолчанию. Однако все проекты, созданные до этой даты, по-прежнему используют токены с полными правами на запись, если администратор вручную не изменил настройку. Таким образом, старые популярные репозитории библиотек могут оказаться уязвимы.
Срок действия GITHUB_TOKEN ограничен: он истекает через час после выдачи, а после завершения задачи GitHub немедленно отзывает токен. Тем не менее исследователи из Sansec и независимый автор уязвимости независимо подтвердили, что между моментом публикации токена в логе и отзывом есть окно для атаки. Если злоумышленник успеет захватить токен, пока задача ещё выполняется, он сможет использовать его для операций записи. В тестах Sansec для этого требовалось менее двух секунд. Если же после вызова Composer в пайплайне выполняются другие шаги - тестирование, сборка, развёртывание - это окно может растянуться на минуты.
Последствия для цепочки поставок PHP крайне серьёзны. Packagist, центральный реестр пакетов PHP, получает релизы напрямую из репозиториев GitHub. Многие разработчики популярных библиотек настраивают CI-пайплайны, которые запускают Composer при каждом push или по расписанию. Если такой пайплайн использует shivammathur/setup-php, токен разработчика с правами записи оказывается в публичном логе (если репозиторий открыт). Атакующий, получив токен, может отправить вредоносный коммит и выпустить новую версию пакета. Другие проекты, выполняющие composer update, автоматически подтянут скомпрометированный код.
Хорошая новость в том, что GitHub временно откатил развёртывание нового формата токенов. По заявлению разработчиков Composer, это даёт несколько дней на обновление, прежде чем rollout возобновится на следующей неделе. Тем не менее, специалистам по безопасности настоятельно рекомендуется как можно скорее обновить Composer во всех CI-пайплайнах. Действие shivammathur/setup-php по умолчанию устанавливает последнюю стабильную версию, поэтому в большинстве случаев исправление будет получено автоматически. Дополнительно стоит проверить настройки прав доступа для GITHUB_TOKEN: на уровне организации или репозитория лучше установить значение read-only, а полный доступ давать только тем задачам, которым он действительно необходим. Наконец, в ближайшее время желательно избегать обновления зависимостей до полной оценки масштаба угрозы.
Уязвимость была обнаружена Дамьеном Ретцингером 12 мая 2026 года, в тот же день он сообщил о ней разработчикам Composer и команде безопасности GitHub. Исправления вышли уже 13 мая. Учитывая массовое использование Composer и CI, это один из самых опасных инцидентов для экосистемы PHP за последнее время.
Ссылки
- https://github.com/composer/composer/security/advisories/GHSA-f9f8-rm49-7jv2
- https://sansec.io/research/composer-github-token-leak