
Скрипт оболочки для обнаружения индикаторов атаки на цепочку поставок TanStack npm (CVE-2026-45321 / GHSA-g7cv-rxg3-hmpx)
Обнаружение индикаторов npm-атаки на цепочку поставок TanStack на рабочей машине разработчика, в репозитории или на CI-раннере. Bash-скрипт, Docker-образ и GitHub Action — один и тот же движок, три точки входа.
CVE-2026-45321 / GHSA-g7cv-rxg3-hmpx
11 мая 2026 года злоумышленники опубликовали 84 вредоносных версии в 42 пакетах @tanstack/* через отравление кэша GitHub Actions. Полезная нагрузка крадет токены GitHub, токены npm, учетные данные AWS/GCP/Azure и устанавливает демон "мёртвой руки", который уничтожает ~/ в момент отзыва украденного токена.
Выберите точку входа, соответствующую вашей среде.
TAG=v1.0.0
curl -fsSLO https://github.com/fabriziosalmi/tanstack-compromise-checker/releases/download/$TAG/check.sh
curl -fsSLO https://github.com/fabriziosalmi/tanstack-compromise-checker/releases/download/$TAG/check.sh.sha256
sha256sum -c check.sh.sha256
bash check.sh --online
docker run --rm -v "$PWD":/scan \
ghcr.io/fabriziosalmi/tanstack-compromise-checker:v1.0.0 \
/scan true fail tanstack-findings.json '' GHSA-g7cv-rxg3-hmpx
Образ является multi-arch (linux/amd64, linux/arm64) и поставляется с проверкой подлинности сборки, подписанной через GitHub OIDC. Проверьте перед запуском:
gh attestation verify \
oci://ghcr.io/fabriziosalmi/tanstack-compromise-checker:v1.0.0 \
--repo fabriziosalmi/tanstack-compromise-checker
permissions: {}
jobs:
check:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
- uses: fabriziosalmi/tanstack-compromise-checker@v1
with:
scan-dir: .
online: 'true'
fail-on: fail
Полный усиленный рабочий процесс находится в
.github/workflows/tanstack-check.yml
и это тот же рабочий процесс, который этот репозиторий запускает против самого себя.
С --online скрипт также получает рекомендацию GHSA во время выполнения, чтобы
покрытие обнаружения отслеживало актуальное состояние рекомендации вместо жёстко заданного списка версий.
Затронутое семейство: @tanstack/router, @tanstack/react-router,
@tanstack/history, @tanstack/start, @tanstack/eslint-plugin-router и
связанные пакеты.
Чистые семейства (не затронуты): @tanstack/react-query,
@tanstack/react-table, @tanstack/react-virtual, @tanstack/form,
@tanstack/store.
# Быстрая проверка (домашняя папка текущего пользователя)
bash check.sh
# Онлайн-режим: запрос к рекомендации GHSA и времени публикации в npm registry
bash check.sh --online
# Сканирование конкретной директории
bash check.sh --scan-dir /path/to/your/repos
# JSON-вывод для интеграции с CI/SIEM
bash check.sh --json > findings.json
# Предложение команд фиксации для затронутых репозиториев (пробный запуск)
bash check.sh --scan-dir /path/to/repos --fix
# Предоставление расширенного списка известных плохих версий
bash check.sh --bad-versions-file ./extra-bad-versions.txt
| Код | Значение |
|---|---|
| 0 | Чисто — нет индикаторов в пределах сканируемой области |
| 1 | Только предупреждения — рекомендуется проверка |
| 2 | Ошибки — присутствуют индикаторы компрометации |
| 3 | Ошибка инструмента/использования |
Этот репозиторий защищается от того же класса атак, которые он обнаруживает. Конкретно:
uses: GitHub Action зафиксировано по 40-символьному SHA коммита, а не по плавающему тегу.permissions: {} на верхнем уровне; задачи предоставляют только то, что им нужно.actions/checkout вызывается с persist-credentials: false, чтобы в $GITHUB_WORKSPACE не оставалось аутентифицированного git-удаленного репозитория.step-security/harden-runner — первый шаг каждого рабочего процесса, отслеживающий исходящие соединения раннера.main; результаты загружаются как SARIF.gh attestation.check.sh.sha256, покрывающим все устанавливаемые артефакты.Полная политика в SECURITY.md.
Не используйте curl | bash для любого инструмента безопасности, включая этот. Всегда
скачивайте, проверяйте контрольную сумму, просматривайте, затем запускайте.
━━ 1 / 8 АРТЕФАКТЫ МЁРТВОЙ РУКИ
✔ Артефактов мёртвой руки не найдено
━━ 2 / 8 ВЕКТОРЫ ПОСТОЯНСТВА
✔ Векторов постоянства не обнаружено
━━ 3 / 8 РАСКРЫТИЕ ТОКЕНОВ / УЧЁТНЫХ ДАННЫХ
✔ Раскрытия учётных данных не обнаружено
━━ 4 / 8 СЕТЕВЫЕ ИНДИКАТОРЫ
✔ В настоящее время TCP-соединений node не установлено (или не наблюдаются)
━━ 5 / 8 СКАНИРОВАНИЕ РЕПОЗИТОРИЯ — package.json + lock-файлы
ℹ Найдено 12 package.json + 8 lock-файлов
✔ Скомпрометированных семейств в package.json не объявлено
✔ Скомпрометированных фиксаций в lock-файлах не найдено
━━ 6 / 8 УСТАНОВЛЕННЫЕ node_modules — прямая проверка версий
✔ Скомпрометированных пакетов в установленных node_modules не найдено
━━ 7 / 8 ПОДСКАЗКИ ПО УСИЛЕНИЮ GITHUB ACTIONS
✔ Опасных паттернов GitHub Actions не обнаружено (в сканируемой области)
━━ 8 / 8 ПОЛЕЗНАЯ НАГРУЗКА MINI SHAI-HULUD + ВСПОМОГАТЕЛЬНЫЕ IOC
✔ Полезной нагрузки Mini Shai-Hulud / вспомогательных IOC не обнаружено
━━ СВОДКА
Пройдено: 8 Предупреждений: 0 Ошибок: 0
Область : /Users/alice/dev
✔ Индикаторов компрометации в области: /Users/alice/dev не обнаружено
Примечание: чистый результат для /Users/alice/dev не подтверждает остальную часть системы.
НЕ отзывайте свой токен GitHub до остановки демона — механизм мёртвой руки выполнит
rm -rf ~/в момент отзыва токена.
launchctl bootout gui/$UID ~/Library/LaunchAgents/com.user.gh-token-monitor.plistlaunchctl unload ~/Library/LaunchAgents/com.user.gh-token-monitor.plistsystemctl --user stop gh-token-monitor && systemctl --user disable gh-token-monitorrm -f ~/.local/bin/gh-token-monitor.sh~/.aws/credentials, ~/.kube/config, ~/.config/gh/hosts.yml,
~/.npmrc.Bash-скрипт требует:
bash 4+jq (рекомендуется) — разбор package-lock.jsonpython3 (необязательный запасной вариант) — используется, когда jq отсутствуетcurl — требуется для --onlinelsof или ss (необязательно) — эвристика сетевых IOCDocker-образ включает всё вышеперечисленное. Используйте его в системах, где вы не можете или не хотите устанавливать эти инструменты.
Приветствуются проблемы (issues) и запросы на слияние (pull requests). Обратите внимание, что в этом репозитории используются CODEOWNERS: все PR требуют проверки мейнтейнером.
MIT.
| # | Проверка | Описание |
|---|
| 1 | Мёртвая рука | ~/.local/bin/gh-token-monitor.sh, LaunchAgents + LaunchDaemons (macOS), systemd user + system units (Linux), запущенные процессы |
| 2 | Постоянство | файлы rc оболочки, crontab пользователя/системы, /etc/cron.*, XDG автозапуск, глобальный git core.hooksPath |
| 3 | Учётные данные | чувствительные переменные окружения, ~/.npmrc, ~/.yarnrc.yml, ~/.aws/credentials, ~/.config/gh/hosts.yml, ~/.netrc, ~/.docker/config.json, ~/.kube/config, перечисление .env* файлов |
| 4 | Сетевые IOC | запущенные процессы node с установленными исходящими TCP-соединениями (эвристика, ручная проверка) |
| 5 | Сканирование репозитория | package.json объявленные зависимости + зафиксированные версии в lock-файлах (package-lock.json, yarn.lock, pnpm-lock.yaml) |
| 6 | Установленные | node_modules/@tanstack/*/package.json проверяется по известному списку вредоносных версий, затем по реестру npm time[<version>] при --online |
| 7 | Подсказки Actions | .github/workflows/* сканируется на pull_request_target, отсутствие --ignore-scripts, использование actions/cache |
| 8 | IOC Mini Shai-Hulud | файлы полезной нагрузки в node_modules (router_init.js, tanstack_runner.js), @tanstack/setup optionalDependency, подделка конфигураций AI-инструментов, C2-домены в исходниках, паттерны автора коммитов и веток атакующего, помеченные как выкуп npm-токены, вторичные распространяемые червём пакеты, а также информационные эвристики для неизвестных форм полезной нагрузки |
| Флаг | Описание |
|---|
--scan-dir DIR | Корневая директория для сканирования (по умолчанию: $HOME). Отказывается сканировать системные директории, такие как /, /etc, /usr. |
--online | Запрос к рекомендации GHSA и time[<version>] реестра npm для подтверждения компрометации. По умолчанию выключено — требуется явное включение. |
--ghsa GHSA-ID | Переопределить идентификатор рекомендации, используемый в --online (по умолчанию GHSA-g7cv-rxg3-hmpx). |
--attack-window-start ISO, --attack-window-end ISO | Переопределить временное окно публикации, используемое в --online. |
--fix | Вывести рекомендуемые команды фиксации для затронутых репозиториев (по умолчанию пробный запуск). |
--apply | С --fix: явное согласие на выполнение. В настоящее время всё ещё отказывается от слепого update; требуется ручная фиксация. |
--yes, -y | Пропустить запрос подтверждения для --apply. |
--json | Выводить результаты в формате JSON в стандартный вывод (подразумевает --quiet). |
--bad-versions-file F | Добавить записи (pkg@version, по одной на строку) в список известных плохих версий. |
--no-color | Отключить ANSI-цвета. |
--quiet, -q | Подавить вывод по каждой проверке, выводить только сводку. |
-h, --help | Показать справку. |