
Эксплойт-доказательство концепции для CVE-2026-44590 — инъекция команд в GitHub Actions workflow Sherlock, позволяющая выполнить произвольный код (RCE) и похитить GITHUB_TOKEN через pull_request_target.
Обнаружено и сообщено: Astaruf
Полное описание: https://nstsec.com/en/posts/sherlock-rce-pull-request-target-cve-2026-44590/
Консультация вышестоящего проекта: sherlock-project/sherlock GHSA advisory
Запись NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-44590
Запись CVE: https://www.cve.org/CVERecord?id=CVE-2026-44590
Этот репозиторий содержит proof-of-concept для CVE-2026-44590 — инъекции команд в GitHub Actions workflow validate_modified_targets.yml проекта sherlock-project/sherlock. Любой пользователь GitHub может открыть pull request, который запускает произвольное выполнение команд в привилегированном контексте CI, похитить GITHUB_TOKEN из workflow и автоматически одобрить вредоносный PR — всё это без какого-либо участия человека.
Для полного технического описания (анализ первопричины, пошаговая эксплуатация, обсуждение последствий и глава о том, что атакующий мог бы сделать в реальных сценариях) см. запись в блоге:
nstsec.com/en/posts/sherlock-rce-pull-request-target-cve-2026-44590
Этот README посвящён исключительно скрипту PoC: что он делает, как его запустить и чего ожидать.
poc.pypoc.py — это единый автономный Python-скрипт (только stdlib), который автоматизирует всю цепочку атаки от начала до конца:
sherlock-project/sherlock, если это необходимоmaster форка к коммиту до исправления, чтобы ошибку можно было воспроизвести даже после исправления в вышестоящем проектеinteractsh-client)GITHUB_TOKEN из OAST-колбэка (в режиме --mode exfil) и декодирует его в открытом видеVULNERABILITY CONFIRMED или FIX VERIFIEDinteractsh-client)Требуется ровно один ручной шаг (нажатие баннера GitHub «I understand my workflows» при первом запуске для каждого форка), поскольку не существует публичного API для его отклонения. Скрипт обнаруживает этот случай и приостанавливается с понятным запросом.
python3 poc.py --fork-owner <ваше-имя-пользователя-github>
Создаёт форк репозитория (при необходимости), синхронизирует с вышестоящим проектом (исправленный master), открывает вредоносный PR, запускает цепочку атаки и сообщает FIX VERIFIED, поскольку исправленный workflow блокирует полезную нагрузку до выполнения каких-либо shell-команд.
python3 poc.py --fork-owner <ваше-имя-пользователя-github> --vulnerable
То же, что и выше, но сначала откатывает master форка к коммиту до исправления (271608fb). Ожидаемый вердикт: VULNERABILITY CONFIRMED.
python3 poc.py --fork-owner <ваше-имя-пользователя-github> --vulnerable --mode exfil
Полезная нагрузка exfil выгружает git config --list на OAST и засыпает на 180 секунд, чтобы поддерживать workflow (и, соответственно, GITHUB_TOKEN) активным. Пока workflow спит, скрипт извлекает токен из журнала OAST, декодирует его и немедленно вызывает GitHub API для одобрения PR. В итоге PR оказывается одобренным от имени github-actions[bot].
gh (GitHub CLI), авторизованный:
gh auth login
gitinteractsh-client (опционально, но рекомендуется). При установке скрипт автоматически запускает его и проверяет колбэк внутри скрипта:
go install github.com/projectdiscovery/interactsh/cmd/interactsh-client@latest
Если вы предпочитаете использовать собственную OAST-конечную точку (Burp Collaborator, oast.fun через веб-интерфейс, requestbin и т. д.), передайте её через --oast-url, и шаг автоматической проверки будет пропущен.Скрипту не требуется заранее существующий форк — он создаёт его автоматически.
--mode harmless (по умолчанию)Полезная нагрузка — это один curl POST со статической строкой подтверждения. Никакие секреты не считываются, никакие API-вызовы не выполняются, единственный побочный эффект — OAST-колбэк. Используйте этот режим, чтобы подтвердить наличие уязвимости без раскрытия каких-либо учётных данных.
--mode exfilПолезная нагрузка выгружает git config --list (который содержит GITHUB_TOKEN в base64-кодировке в http.https://github.com/.extraheader) на OAST, а затем засыпает на 180 секунд. Затем скрипт:
x-access-token:ghs_XXXXXXXX....x-access-token: и использует исходный токен для вызова POST /repos/<fork>/pulls/<n>/reviews со стандартной полезной нагрузкой одобрения ({"event":"APPROVE","body":"All checks passed. LGTM!"}).github-actions[bot], неотличимый от легитимной CI-автоматизации.После фиксации одобрения скрипт пропускает оставшуюся часть 180-секундного ожидания workflow, поскольку цепочка атаки завершена, и ожидание тайм-аута раннера ничего не добавляет.
| Флаг | Описание |
|---|---|
--fork-owner <user> | Обязательный. Имя пользователя GitHub, которому принадлежит (или будет принадлежать) форк |
--fork-name <name> | Имя репозитория форка (по умолчанию: sherlock) |
--oast-url <url> | OAST-конечная точка, принимающая колбэк. Если не указан, скрипт автоматически запускает interactsh-client и выполняет вердикт внутри скрипта |
--mode harmless|exfil | Тип полезной нагрузки (по умолчанию: harmless) |
--vulnerable | Принудительный сброс master форка к коммиту до исправления (271608fb) перед запуском. Подразумевает --no-sync |
--no-sync | Пропустить синхронизацию форка с вышестоящим проектом (полезно при тестировании зафиксированного коммита) |
--base-branch <name> | Целевая ветка PR в форке (по умолчанию: master) |
--keep-branch | Не удалять ветку PoC после завершения |
--no-poll | Пропустить опрос запуска workflow и выйти после создания PR |
По замыслу PoC открывает PR из ветки в форке на master того же форка. Он не направлен напрямую на sherlock-project/sherlock. Для этого есть две причины.