КИБЕРБЕЗОПАСНОСТЬ

npm-червь через Keyv отравил сотни пакетов и добавил хуки в VS Code

353 вредоносные версии в npm: npm-червь через Keyv крадет токены и ключи, а хуки Claude Code и VS Code дают ему второй путь запуска в репозитории.

✍️ Редакция iTech News | 05.08.2026 | ⏱ 5 мин | Источник: The Hacker News

Минимум 353 вредоносные версии в npm оказались частью кампании, начавшейся с keyv@6.0.0 и за считаные часы разошедшейся по сотням артефактов в реестре. Этот npm-червь интересен не только масштабом: он крадет токены, приватные ключи и умеет сам продолжать заражение через чужие права на публикацию. Для команд, которые держат Node.js в проде, это уже не история про один неудачный релиз, а тест на зрелость всей цепочки поставки — от lockfile до CI runner.

Как пишет The Hacker News, SafeDep сначала подтвердил 353 зараженные версии по 79 именам пакетов в npm, а его мониторинг оценил более широкий след в 442 версиях по 353 именам. Позже Aikido сообщил как минимум о 868 пакетах и 1381 версии, а затем SafeDep обновил свою собственную оценку до 1684 вредоносных версий по 420 пакетным именам, связанным с девятью организациями. Эти числа нельзя складывать в одну сенсационную сумму: компании использовали разные выборки, а полного публичного списка на момент публикации не существовало. Но даже нижняя граница уже неприятная — речь идет не о компрометации одного популярного пакета, а о машинном распространении через чужие издательские учетки.

Первая подтвержденная точка входа — keyv@6.0.0. В пакет добавили preinstall-команду node setup.mjs и два файла, setup.mjs и Math_Symbol.js, при том что собранная библиотека осталась прежней. На этом и строится ловушка: код, который разработчик ожидает увидеть, почти не меняется, а вредонос срабатывает еще до того, как пакет попадает в реальное исполнение приложения. По разбору SafeDep, первая стадия проверяет наличие Bun, при необходимости скачивает Bun 1.3.13 с официальных GitHub Releases и передает исполнение крупному скомпилированному бандлу размером 727 680 байт. Дальше bundle идет по самому болезненному месту современной разработки: забирает GitHub- и npm-токены, облачные секреты, данные Vault, Kubernetes, баз данных, приватные ключи и читает память GitHub Actions runner.

Socket отдельно расшифровал логику, которая умеет модифицировать пакеты, повышать версии и заново публиковать их от имени украденной npm-учетки. На этом история не заканчивается реестром. В репозитории Keyv остались два дополнительных хука: в .claude/settings.json был SessionStart, вызывающий .vscode/setup.mjs, а в .vscode/tasks.json — задача Environment Setup с runOn: folderOpen, которая дергала .claude/setup.mjs. То есть npm-червь получил еще и маршрут через checkout репозитория: не только через install, но и через рабочее пространство редактора. Важная оговорка: эти пути не срабатывают безусловно. VS Code по умолчанию блокирует автоматические задачи в недоверенном workspace и спрашивает разрешение, а Claude Code применяет доверие рабочего пространства к настройкам проекта.

Самый неприятный здесь даже не Bun и не preinstall, а то, как красиво все выглядело на бумаге. Зараженный релиз прошел через легитимный GitHub Actions-пайплайн и получил валидную OIDC/SLSA provenance: аттестация честно подтверждала, что пакет собран штатным процессом. Проблема в том, что штатный процесс упаковал вредоносный исходник. Коммит, который посадил Claude Code- и VS Code-хуки, имел зеленый GitHub-verified badge и автора github-actions[bot], но это тоже не отвечает на вопрос, кто именно контролировал credential в момент публикации. SafeDep видел тот же payload и под напрямую скомпрометированными npm-аккаунтами, поэтому всплеск очень похож на автоматизированное распространение, но не позволяет уверенно посчитать число взломанных учеток.

Картина в самом npm менялась так быстро, что проверки по текущему состоянию реестра почти бессмысленны. По данным SafeDep, уже к 17:40 по индийскому времени 4 августа для как минимум девяти пакетов из первоначального списка тег latest откатили на прежние версии, среди примеров назывались keyv@5.6.0, flat-cache@6.1.23 и cache-manager@7.2.9. Поэтому вопрос «пакет сейчас чистый?» здесь вторичен. Гораздо важнее другой: какая точная версия реально разрешилась на конкретной машине и выполнился ли lifecycle script. Исследователи отдельно подчеркивают, что их цифры — это число вредоносных артефактов в реестре, а не число скомпрометированных систем. Не все, что связано с мейнтейнером, было заражено: адаптеры @keyv/* и ветка Keyv 5.x, по данным SafeDep, оставались чистыми.

Для разработчиков, платформенных команд и бизнеса вывод предельно практический. Если затронутая версия успела выполниться на рабочей станции или в CI, такую среду SafeDep и Socket советуют считать скомпрометированной, а не просто подозрительной. Причем порядок реакции важен: сначала нужно убрать watcher, который отслеживает отзыв токенов и может запускать локальный обработчик злоумышленника, и только потом ротировать секреты. Иначе сам отзыв ключа становится триггером. npm 12 по умолчанию уже блокирует неразрешенные dependency lifecycle scripts, но старые клиенты npm и другие сценарии установки, где lifecycle-скрипты разрешены, остаются уязвимыми. Для русскоязычных команд это прямой повод пересмотреть политику install scripts, правила доверия к workspace и изоляцию CI-раннеров, особенно если публикация пакетов завязана на общие сервисные токены.

Контекст у этой кампании тоже тревожный. Semgrep увидел те же артефакты — хуки для Claude Code и VS Code, файл setup.mjs и скачивание Bun 1.3.13 — в апрельском компромиссе пакета lightning в PyPI, а Aikido относит августовскую волну к семейству Shai-Hulud. Это еще не атрибуция и не доказательство единого оператора, но уже вполне похоже на повторяемый шаблон: сначала крадем издательские права, потом превращаем доверенную экосистему в средство самораспространения. SafeDep вдобавок насчитал 546 публичных GitHub-репозиториев, созданных 4 августа с описанием Shai-Hulud: Here We Go Again и каталогом results/; это скорее следы эксфильтрации или staging, чем список жертв. Публичных заявлений от мейнтейнера, npm и GitHub на момент публикации не было. Главный вопрос теперь не в том, сколько еще пакетов всплывет в списке, а в том, сколько команд до сих пор путают «подписано и собрано штатно» с «источник безопасен».

Поделиться: Telegram X LinkedIn