Угрозы

GitHub Actions закрыл опасный сценарий с pull_request_target и checkout кода из форков

Маша Даровская
By Маша Даровская , IT-редактор и автор
GitHub Actions закрыл опасный сценарий с pull_request_target и checkout кода из форков
Обложка © Anonhaven

GitHub изменил поведение actions/checkout — одного из самых популярных действий в GitHub Actions. Новая версия actions/checkout@v7 по умолчанию отказывается извлекать код из непроверенного pull request, если workflow запущен через pull_request_target или через связанный с pull request сценарий workflow_run.

Это закрывает один из самых неприятных и давно известных классов ошибок в CI/CD: pwn request. Так называют ситуацию, когда злоумышленник отправляет pull request из форка, а привилегированный workflow в основном репозитории сам забирает его код и запускает команды с доступом к секретам, токенам и правам проекта.

GitHub уже включил защиту в actions/checkout@v7. 16 июля 2026 года компания перенесет новое поведение на все поддерживаемые мажорные версии. Если проект использует плавающий тег вроде actions/checkout@v4, защита приедет автоматически. Если workflow закреплен на конкретный SHA, minor- или patch-версию, обновление придется сделать вручную через Dependabot или обычный процесс апдейта зависимостей.

Раньше actions/checkout мог спокойно забрать код из pull request от внешнего автора даже внутри workflow, который запущен через pull_request_target. Для многих проектов это выглядело удобно: нужно проверить изменения из PR, значит надо скачать ветку автора и прогнать тесты.

Проблема в контексте запуска. pull_request_target выполняет workflow от имени базового репозитория, а не форка. Такой workflow может получать доступ к GITHUB_TOKEN, секретам, кешам, окружению runner и правам, которые недоступны обычному pull request из форка.

Если в таком режиме забрать код внешнего автора и выполнить npm install, тесты, сборку, локальный скрипт или действие из репозитория, атакующий получает шанс запустить свой код в привилегированной среде.

Теперь actions/checkout@v7 распознает типовые опасные варианты. Он блокирует checkout, если workflow с привилегированным триггером пытается забрать код из форка pull request: head-ветку, merge-ref, SHA коммита из форка или сам репозиторий форка.

Под блокировку попадают конструкции вроде:

ref: refs/pull/${{ github.event.pull_request.number }}/merge

ref: ${{ github.event.pull_request.head.sha }}

repository: ${{ github.event.pull_request.head.repo.full_name }}

Именно такие настройки часто встречались в уязвимых workflow: на вид обычная проверка PR, фактически — запуск чужого кода с правами основного проекта.

pull_request_target не является ошибкой сам по себе. Он нужен для задач, где workflow должен работать с правами основного репозитория: ставить метки, комментировать pull request, проверять метаданные, назначать ревьюеров, работать с triage-автоматизацией.

Опасность появляется, когда такой workflow начинает выполнять код из pull request. Тут важно разделить две вещи.

Файл workflow берется из доверенной ветки основного репозитория. Это создает ощущение безопасности. Но код, который workflow скачивает и запускает, может прийти из форка злоумышленника. А значит, package.json, install-скрипты, тесты, локальные actions, shell-команды и helper-скрипты уже находятся под контролем автора pull request.

Один невинный шаг вроде установки зависимостей может стать точкой входа. В экосистеме JavaScript lifecycle-скрипты npm могут запускаться автоматически, если их не отключить. В других языках похожую роль играют build hooks, тестовые раннеры, генераторы кода и пользовательские скрипты.

GitHub Security Lab предупреждала об этом риске еще в 2021 году. Исследователи писали, что связка pull_request_target и явного checkout непроверенного PR может привести к компрометации репозитория, краже секретов или получению прав на запись.

Долгое время это оставалось проблемой настройки. Документация предупреждала, инструменты статического анализа искали опасные workflow, эксперты писали гайды, но уязвимые конфигурации продолжали появляться в реальных проектах.

Причина: поддерживающим open source нужен удобный способ обрабатывать pull request из форков. Они добавляют pull_request_target, потому что обычный pull_request не дает нужных прав. Затем добавляют checkout кода PR, потому что надо прогнать проверки. На этом месте защита ломается.

Socket связывает такие ошибки с несколькими заметными инцидентами в экосистеме npm, включая Nx, вторую волну Shai-Hulud и компрометацию TanStack. GitHub Actions становился частью пути к токенам, публикации пакетов или запуску вредоносного кода в релизной среде.

Новая логика в actions/checkout не запрещает pull_request_target полностью. Она устраняет эксплуатацию опасного сочетания: привилегированный workflow плюс checkout кода из внешнего форка.

Обычные pull request из того же репозитория не затронуты. Триггер pull_request тоже работает как раньше. GitHub не ломает стандартный CI для внешних вкладов, если не получает расширенные права базового репозитория.

Для редких случаев, где команде действительно нужно прежнее поведение, добавлен явный флаг:

allow-unsafe-pr-checkout: true

Это азрешение на небезопасный checkout. Такой флаг будет легко найти в ревью, grep-поиске и автоматических проверках.

Использовать его стоит только после отдельного разбора рисков. Если workflow с этим флагом имеет доступ к секретам, публикации пакетов, deployment-правам, кешам или OIDC, его нужно считать высокорисковым.

Первое место для ревизии — .github/workflows. Нужно найти все workflow с pull_request_target и посмотреть, есть ли там checkout кода из PR.

Особенно опасны сочетания с такими признаками:

on: pull_request_target

github.event.pull_request.head.sha

github.event.pull_request.head.repo.full_name

refs/pull/

npm install

npm test

pnpm install

yarn install

uses: ./

permissions: write-all

id-token: write

Если workflow нужен только для меток, комментариев и triage, ему часто вообще не нужен checkout. Если нужно тестировать код из PR, безопаснее запускать это через pull_request с минимальными правами и без секретов.

Публикацию пакетов, деплой и работу с продакшен-секретами лучше держать в отдельных workflow, которые запускаются только после доверенного события: merge в защищенную ветку, релизный тег, ручное подтверждение, environment protection или другой контролируемый процесс.

Проекты с actions/checkout@v7 уже получают новое поведение. Проекты с плавающими мажорными тегами вроде actions/checkout@v4 получат защиту автоматически после бэкпорта 16 июля 2026 года.

Хуже ситуация у тех, кто закрепил checkout на точный коммит или конкретную версию. Такой подход обычно используют ради воспроизводимости и защиты от supply chain-рисков.

Таким проектам нужно отдельно обновить ссылку на actions/checkout, проверить, не сломались ли workflow, и зафиксировать новое безопасное поведение. Хорошая практика — включить Dependabot для GitHub Actions, чтобы такие обновления попадали в обычный процесс ревью.

Есть новость? Станьте автором.

Мы сотрудничаем с независимыми исследователями и специалистами по кибербезопасности. Отправьте нам новость или предложите статью на рассмотрение редакции.