Класс атак где злоумышленник публикует малварь в публичном registry (npm, PyPI) и она запускается у каждого кто эту зависимость поставил. Триггер у нас — Shai-Hulud 2.0 ноября 2025: преинсталл-скрипт в @postman/tunnel-agent (через transitive dep от npx @usebruno/cli) создал GitHub PAT с правами на 42 приватных репо Realai-plus, развернул self-hosted runner и пытался lateral movement.1 Свежее напоминание — mini-Shai-Hulud в мае 2026 (~400 пакетов на TanStack + PyPI, начало с mistral).2
Где запускается малварь
При установке пакета, не во время рантайма — через preinstall/postinstall скрипты (npm) или setup.py build hooks (PyPI). Это значит защита должна стоять до того как pip install или pnpm install физически распакует пакет. Container runtime-сканирование такую атаку не ловит — заражение уже произошло на этапе билда контейнера, у малвари было время украсть креды.
Чему уязвимы
Любая dev-машина, любой CI runner, любой Dockerfile делающий npm install или pip install. Малварь оттуда:
- Крадёт credentials (
~/.config/gcloud,~/.ssh, GitHub OAuth, npm publish-токены) - Создаёт публичные репозитории со слитыми данными (
Sha1-Hulud: The Second Comingпаттерн в описании) - Деплоит self-hosted GH Actions runner (
SHA1HULUDв имени) - Пытается lateral movement в организацию через украденные PAT-токены
Конкретные IoC (что искать на машине и в org) и playbook первого часа — в security-incident-response.
Где ставится защита
Защита нужна в нескольких местах жизненного цикла зависимости. Ни одна точка не закрывает всё — нужна комбинация. Какие конкретно инструменты выбираем — supply-chain-defense-stack; здесь — что куда ставится и почему.
До установки — pre-install gate. Задержка установки свежих версий: большинство malicious-версий yank’ают из registry за часы, 1-2 дня задержки убирают smash-and-grab волны. Запрет preinstall/postinstall lifecycle-скриптов убирает основной канал заражения целиком. Hash-pinning защищает от подмены версии на лету. Это самый дешёвый и сильный слой — если бы он стоял в ноябре, заражение через @postman/tunnel-agent (свежая версия пакета моложе суток) не прошло бы.
На этапе install — malicious-behavior detection. Статический анализ кода и метаданных пакета: install-scripts, network calls, обфускация, exec-base64 паттерны. Главное достоинство — ловит свежую малварь до того как она попадёт в advisory-базу. Без этого слоя свежий злой пакет проходит мимо CVE-сканеров на 1-3 дня.
После установки — vulnerability scan. Поиск известных CVE по lock-files. Закрывает накопленные дыры с публичными advisory. Слабость: новую малварь не ловит, потому что advisory выходит позже факта компрометации.
Эти три точки не взаимозаменяемы. CVE-сканер не поймает Shai-Hulud потому что advisory ещё не вышло. Malicious-сканер не поймает накопленную дыру в glob 10.4.2. Pre-install gate не делает discovery — но останавливает большую часть smash-and-grab атак. Старый спор «Snyk vs Google Cloud Security Command Center» из ноябрьского обсуждения — ложная дихотомия: оба про vulnerability-сканеры, не про детекцию свежей малвари.1
Кто что настраивает у нас
Разработчик — глобальные настройки на своей dev-машине (~/.npmrc, ~/.config/uv/uv.toml), локально установленные сканеры (osv-scanner, guarddog, pip-audit). Защищает и работу в монорепо, и pet-projects вне его. Конкретный onboarding — security-onboarding.
DevOps — централизованные guards: container CVE-сканинг на Google Artifact Registry, required workflows через Realai-plus/.github-private для прогона security-сканеров на всех приватных репо org, allowed actions allowlist, опционально GAR virtual repos как централизованный package proxy. Решение по конкретному стеку — supply-chain-defense-stack.
Per-репо в монорепо — .npmrc в репо дублирует глобальные настройки разработчика; защищает случай когда новый разработчик с дефолтным сетапом или CI runner делает install. Включено в bloodgpt-frontend (PR #276) и bloodgpt-for-business (PR #25); остальные репо — audit pending.
Что было сделано после ноябрьского инцидента
- PAT-токены отключены на уровне Realai-plus org (через GitHub org settings)
minimum-release-age: 2880иignore-scriptsвbloodgpt-frontend(PR #276) иbloodgpt-for-business(PR #25)- BG-612 заведён в Linear под compliance follow-up
- Письма SOC2-аудитору подготовлены; OCPDP Cyprus не уведомляли — фактической утечки данных не было (PAT создан малварью и быстро detect’нут)
Tooling-стратегия после инцидента была вынесена на пятничный DevOps Sync 28 нояб 2025. Verified в Fireflies: на синке обсуждали логирование, аудит-логи, регионы, репликацию БД — supply-chain так и не обсудили.3 Вопрос повис до мая 2026, supply-chain-defense-stack предлагает разрешение.
Открытые вопросы
- Audit оставшихся репозиториев монорепо (
b2c-dashboard,b2b-api,analysis-worker,normalization-pipeline,loinc-harmonization,bloodgpt-food-search,bloodgpt-e2e-tests) на наличие.npmrcс release-age + ignore-scripts - Включён ли container CVE scanner на staging artifact registry (предположение из ноябрьского треда, не verified)
- Required workflows через
Realai-plus/.github-private— какие workflow’ы whitelist’им, в каком составе
Связанные решения
- supply-chain-defense-stack — какие инструменты выбираем на каждом уровне (pre-install / malicious-behavior / CVE / proxy)
Связано
- security-onboarding — что должен сделать каждый разработчик
- security-incident-response — что делать если случилось, IoC, playbook первого часа
Сноски
-
Slack thread в
#security-reporting, 2025-11-26, https://realaicorp.slack.com/archives/C09GBEVRQEP/p1764142896295519 — расследование утечки PAT через Shai-Hulud 2.0, мнения Жени и Артёма по tooling-стратегии. ↩ ↩2 -
Socket blog, mini-Shai-Hulud на TanStack + PyPI, 2026-05-11, https://socket.dev/blog/tanstack-npm-packages-compromised-mini-shai-hulud-supply-chain-attack — атака продолжалась 2026-05-11..12. ↩
-
DevOps Sync, 2025-11-28, https://github.com/Realai-plus/meeting-digests/blob/main/data/digest/2025/11/2025-11-28T12%3A00%3A47.000Z_DevOps_Sync_01KB55CNPD7FE6A7964R9WM8E6.md — час 11 минут обсуждали логирование (ELK vs Loki), аудит-логи, регионы, репликацию БД; supply-chain не поднимался. ↩