WeaselBiscuit и вредоносные npm-пакеты: почему browser storage стал целью
Virusologia briefing: проблема, доказательства, defensive-контроль и ретест.
Коротко: Новая волна вредоносных npm-пакетов показывает неприятный сдвиг: атакующим всё чаще нужны не только файлы проекта, а данные браузерных расширений, токены разработчика и контекст рабочей станции.

Проблема

Supply-chain атака через npm больше не выглядит как редкий edge-case. Маленький пакет может оказаться точкой входа в рабочую машину разработчика, CI-контур или браузерный профиль, где живут токены, расширения и следы доступа к SaaS-инструментам.

Опасность не только в самом пакете. Опасность в доверии к install-time действиям, в неразделённых профилях браузера и в том, что developer endpoint часто имеет больше доступа к продукту, чем обычный офисный ноутбук.

Что проверить

  • Есть ли запрет или аудит install scripts в npm/pnpm/yarn для production и CI.
  • Отделены ли рабочие браузерные профили от личных и тестовых расширений.
  • Можно ли быстро отозвать npm tokens, Git tokens, cloud keys и OAuth grants после подозрительного install.
  • Логируются ли обращения к секретам и скачивание зависимостей в CI.
  • Есть ли allowlist registry/proxy и lockfile review для критичных репозиториев.

Решение

Минимальная зрелая защита начинается с dependency proxy, lockfile-diff review, запрета неожиданных postinstall hooks и отдельной политики для developer workstations.

Для SOC полезнее не алерт на слово stealer, а корреляция: новый пакет, запуск неизвестного node-процесса, чтение browser storage, сетевой выход к новому домену, затем обращение к репозиториям или SaaS.

Defensive-чеклист

  • Проверить npmrc и registry policy.
  • Включить secret scanning на репозиториях и CI artifacts.
  • Ротировать developer tokens при любом подтверждённом подозрительном install.
  • Выделить browser extension storage как forensic source, но не складывать сырые токены в отчёты.
  • Добавить tabletop-сценарий: malicious package на машине разработчика.

Безопасный пример

# безопасная проверка lockfile: ищем lifecycle scripts без выполнения пакетов
import json
from pathlib import Path

package = json.loads(Path("package.json").read_text(encoding="utf-8"))
scripts = package.get("scripts", {})
for name in ("preinstall", "install", "postinstall", "prepare"):
    if name in scripts:
        print(f"review_required: {name} -> {scripts[name]}")
Этическая рамка: материал предназначен для defensive security, легального аудита собственных систем, обучения и подготовки remediation. Он не содержит эксплуатационных цепочек, вредоносных payload или инструкций по обходу защиты.