Червь Keyv захватил сотни пакетов npm

4 августа 2026 года похищающий учётные данные червь, связанный с пространствами имён Keyv и Cacheable, распространился по пакетам npm нескольких организаций. SafeDep сначала подтвердил 353 заражённые версии 79 пакетов, а расширенный мониторинг компании насчитал 442 версии среди 353 наименований. Aikido позднее сообщил как минимум о 868 пакетах и 1381 версии. После дополнительной проверки реестра SafeDep заменил прежние цифры новой оценкой: 1684 отравленные версии 420 пакетов, связанных с девятью организациями. По наблюдениям компании, червь переходил между организациями каждые две-семь минут, а вся межорганизационная публикация заняла примерно полчаса.
Цифры SafeDep и Aikido складывать нельзя: компании считали артефакты по разным методикам и с разным охватом. У Aikido больше наименований пакетов, у обновлённого подсчёта SafeDep больше отдельных версий; ранние общие оценки к тому же не удалось независимо воспроизвести по полному публичному списку. Речь идёт о вредоносных пакетных артефактах, а не о числе заражённых компьютеров или доказанных жертв. Реальная угроза для конкретной машины зависит от того, какая версия разрешилась при установке и запускался ли lifecycle-скрипт npm.
В заражённый релиз добавили preinstall-команду node setup.mjs, а в состав пакета вошли файлы setup.mjs и Math_Symbol.js. Скомпилированный код самой библиотеки, по имеющимся данным, не меняли: вредоносная логика срабатывала отдельно во время установки зависимости на рабочей станции, CI-сервере или сборочном раннере. Первый загрузчик проверял наличие Bun, при необходимости скачивал официальную сборку Bun 1.3.13 из GitHub Releases и передавал управление скомпилированному модулю размером 727 680 байт. Официальный источник Bun тут ничего не гарантировал: легитимная среда выполнения использовалась для запуска чужого вредоносного кода. Название и номер первой подтверждённой заражённой версии в доступных данных не сохранились.
Разбор SafeDep показал охоту за данными GitHub и npm, доступом к облакам, секретами Vault, конфигурацией Kubernetes, паролями баз данных, приватными ключами, репозиторными секретами и учётными данными реестров пакетов. Модуль пытался извлекать содержимое памяти раннеров GitHub Actions, устанавливал наблюдатель за отзывом токенов и содержал механизм публикации в npm. Socket отдельно расшифровал функции изменения пакетов, повышения их версий и повторной публикации от имени npm-пользователя, чей доступ удалось украсть. Поэтому скомпрометированная учётная запись издателя превращалась в средство автоматического заражения следующих пакетов.
Самая неприятная ловушка ждала администраторов при реагировании. Червь ставил локальный наблюдатель за отзывом учётных данных, причём именно отзыв служил для него триггером: поспешная ротация токенов или ключей могла запустить оставленный атакующим обработчик. SafeDep рекомендовала сначала найти и удалить этот watcher, а уже потом отзывать секреты. Socket предложил считать раскрытой всю среду, где исполнилась заражённая версия. npm 12 по умолчанию блокирует неодобренные lifecycle-скрипты зависимостей, но старые клиенты и конфигурации, разрешающие install-скрипты, остаются уязвимыми. Если код уже запускался, переход на npm 12 задним числом машину не очистит.
Состояние npm менялось слишком быстро, чтобы список пакетов с вредоносным тегом latest оставался точным. В 17:40 по индийскому стандартному времени 4 августа 2026 года страницы как минимум девяти пакетов из первоначальной выборки SafeDep уже показывали прежние, внешне чистые релизы как latest, однако их названия в сохранившихся данных отсутствуют. Позднее заражённые релизы Keyv и Cacheable сняли с публикации, но у большинства остальных затронутых пакетов latest всё ещё указывал на вредоносную версию. Обычное обновление поэтому могло сохранить заражение или вернуть его. Проверять нужно точные имена и разрешившиеся версии по lock-файлам, журналам установки и CI, а также выяснять, разрешался ли запуск lifecycle-скриптов. Блокировка целого namespace груба: она пропустит пакеты за его пределами и одновременно пометит чистые релизы.
В репозитории Keyv существовал отдельный путь исполнения, не связанный с npm preinstall. Файл .claude/settings.json содержал хук SessionStart, вызывавший .vscode/setup.mjs. В .vscode/tasks.json находилась задача Environment Setup с параметром runOn: folderOpen, запускавшая .claude/setup.mjs. Так код мог сработать после клонирования репозитория. Автоматического запуска в любой стандартной установке всё же не было: VS Code блокирует задачи в недоверенном рабочем пространстве и обычно запрашивает разрешение, а Claude Code применяет проверку доверия к проектным настройкам. Опасность возникала после доверия репозиторию или явного разрешения его конфигурации.
В 17:40 IST 4 августа оба набора хуков оставались в ветке main. Манифест core/keyv/package.json по-прежнему объявлял версию 6.0.0, сохранял node setup.mjs в preinstall и включал setup.mjs с Math_Symbol.js в публикуемые файлы. Более поздняя свежая проверка снова обнаружила каталоги .claude и .vscode вместе с файлами этого маршрута запуска. При этом опубликованные адаптеры @keyv/ и ветка Keyv 5.x, по данным SafeDep, оставались чистыми. Но последующий коммит разложил файлы полезной нагрузки по всем 19 workspace-пакетам, поэтому новый релиз из неочищенного дерева мог занести их в публикацию.
Заражённый релиз Keyv имел действительные аттестации OpenID Connect, или OIDC, и Supply-chain Levels for Software Artifacts, SLSA: пакет прошёл через настоящий release workflow проекта в GitHub Actions. Такая provenance-запись верно удостоверяла процесс сборки и публикации, но не безопасность поступившего в него исходного кода. Коммит с хуками Claude Code и VS Code также получил зелёную отметку GitHub Verified, а автором был указан github-actions[bot]. Проверенная подпись подтверждает подпись, поле автора сообщает лишь записанное имя. Ни один из этих признаков не раскрывает, кто управлял отправившим изменения доступом и действительно ли правку инициировала штатная автоматизация.
SafeDep обнаружила тот же модуль у прямых npm-издателей в других частях кампании. Темп заражения и публикация целыми пространствами имён похожи на автоматическое распространение, хотя исследователи не восстановили запускающую его функцию. Неясно, работал червь через одну похищенную издательскую учётную запись или через несколько независимо захваченных доступов; число публикаций не равно числу взломанных npm-аккаунтов. Semgrep нашёл сходные детали в апрельском взломе PyPI-пакета lightning: хуки Claude Code и VS Code, имя setup.mjs и загрузку Bun 1.3.13. Aikido отнесла августовскую кампанию к семейству Shai-Hulud. Совпадение связывает инструментарий, но не называет оператора, не раскрывает первоначальный способ проникновения и не доказывает, что за апрельским и августовским эпизодами стояли одни люди.
Исследователи насчитали 546 публичных репозиториев GitHub, созданных 4 августа 2026 года, с описанием Shai-Hulud: Here We Go Again («Шаи-Хулуд: и вот опять») и каталогом results/. Их рассматривают как возможные места выгрузки похищенных данных либо промежуточного хранения, а не как 546 подтверждённых жертв. К моменту завершения сбора сведений публичных заявлений сопровождающего проекта, npm или GitHub найти не удалось. Не были установлены также именованный злоумышленник, точное число пострадавших систем и полный набор первоначально затронутых пакетов.
Проверка инцидента должна начинаться с lock-файлов и фактически разрешённых версий, а не с текущих тегов npm. Нужно изучить рабочие станции разработчиков, CI-раннеры, GitHub Actions, npm-аккаунты, облачные учётные записи, Vault, Kubernetes, базы данных и приватные ключи; отдельно проверить наличие .claude/settings.json, .vscode/tasks.json, .claude/setup.mjs, .vscode/setup.mjs, setup.mjs и Math_Symbol.js. Следует пересмотреть решения о доверии рабочим пространствам Claude Code и VS Code, отключить ненужные install-скрипты и установить, исполнялась ли полезная нагрузка. На сработавшей машине сначала удаляют наблюдатель за отзывом учётных данных, затем меняют токены GitHub и npm, облачные доступы, секреты Vault, реквизиты Kubernetes и баз данных, приватные ключи и прочие доступные процессу секреты.


Новое на сайте

Ссылка