Класс атак где злоумышленник публикует малварь в публичном 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)

Связано

Сноски

  1. Slack thread в #security-reporting, 2025-11-26, https://realaicorp.slack.com/archives/C09GBEVRQEP/p1764142896295519 — расследование утечки PAT через Shai-Hulud 2.0, мнения Жени и Артёма по tooling-стратегии. 2

  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.

  3. 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 не поднимался.