Пакетный менеджер npm попал в неприятную историю, которая снова возродила споры о принципах работы реестра с микрозависимостями для JavaScript (и Node.js).
Критики утверждают, что уровень зависимостей в npm слишком большой. Многие помнят историю 2016 года с микромодулем
left-pad
из нескольких строчек кода, которые реализуют примитивную функцию вставки пробелов в левой части строк. Он был установлен в качестве зависимости в React, Babel и других пакетах. Автор и мейнтейнер left-pad
решил в знак протеста отозвать его, что вызвало массовый сбой в работе веб-сайтов. После этого компания npm Inc. запретила авторам отзывать свои пакеты без разрешения администрации.Сейчас мы наблюдаем в каком-то смысле продолжение этой истории.
Пакет everything
В январе 2024 года пользователь под ником PatrickJS (он же gdi2290) с группой контрибуторов в качестве троллинга выложил демонстрационный пакет
everything
с пятью подпакетами. По статистике socket.dev, пакет скачали из реестра около 370 раз.
В соответствии с названием, пакет с подпакетами включал в себя ссылки на все публичные пакеты npm, генерируя миллионы транзитивных зависимостей.
Такой пакет по сути запускает DoS в любой системе, где инициирована установка. Теоретически, злоумышленник может вывести из строя посторонний компьютер простой командой
npm install everything
.Автор даже запустил демонстрационную страничку сайт everything.npm.lol, где показан процесс установки пакета и весь хаос, который возникает при этом. В финале демонстрации запускается сцена из игры Skyrim.
Содержимое файла package.json (код уже удалён с Github):
{
"name": "everything",
"version": "3.0.0",
"description": "npm install everything",
"main": "index.js",
"contributors": [
"PatrickJS <github@patrickjs.com>",
"uncenter <hi@uncenter.dev>",
"ChatGPT <chatgpt@openai.com>",
"trash <trash@trash.dev>",
"Hacksore <sean@boult.me>"
],
"scripts": {},
"keywords": [
"everything",
"allthethings",
"everymodule"
],
"license": "MIT",
"homepage": "https://github.com/everything-registry/everything",
"repository": {
"type": "git",
"url": "git+https://github.com/everything-registry/everything.git"
},
"dependencies": {
"@everything-registry/chunk-0": "0.1.0",
"@everything-registry/chunk-1": "0.1.0",
"@everything-registry/chunk-2": "0.1.0",
"@everything-registry/chunk-3": "0.1.0",
"@everything-registry/chunk-4": "0.1.0"
}
}
Менеджер пакетов npm
Менеджер пакетов npm включён в программу установки Node.js и является менеджером по умолчанию в этой среде выполнения. Он состоит из клиента командной строки и онлайн-базы данных публичных и платных пакетов (реестр npm). Доступ к реестру осуществляется через клиент, а доступные пакеты можно просматривать и искать на сайте npm. Менеджер пакетов и реестр управляются компанией npm, Inc.
Это не первый случай публикации в реестре пакета со всеми возможными зависимостями. В прошлом году состоялся аналогичный перфоманс от автора
no-one-left-behind
. Его удалили, но он затем возродился под другим названием с более чем 33 000 подпакетов. А вообще самым первым таким в 2012 году стал
hoarders
с зависимостями от 20 000 пакетов, который распространялся как «самый полный пакет утилит для node.js». Спустя год hoarders
был удалён лично Исааком Шлётером, создателем npm, по причине большой нагрузки на реестр.Последствия
Как известно, по новым правилам npm (см. выше про инцидент с
left-pad
) разработчиков лишили возможности самостоятельно удалять пакеты из реестра спустя 24 часа после публикации. Поскольку установка everything
автоматически вызывает DoS-атаку на любом компьютере, автора теоретически могли привлечь к уголовной ответственности за умышленное повреждение компьютерных систем. Осознав последствия своего поступка, PatrickJS попытался отозвать пакет, но не смог этого сделать самостоятельно. Ему пришлось обращаться за помощью в техподдержку компании npm Inc.PatrickJS также опубликовал извинение на Github (теперь удалено), в котором попросил прощения за трудности, которые вызвал этот пакет: «Основная проблема заключается в том, что когда пакет зависит от другого пакета определённой версии, эта версия не может быть отозвана, — пишет автор. — С тех пор мы осознали проблему со «звёздными» версиями, которые зависят от любой/всех версий другого пакета (
"package-xyz": "*"
) — никакая версия такого пакета не может быть отозвана из реестра. Как я уже говорил, мы связались с npm и надеемся, что они помогут… Мы сами ничего не можем сделать, у нас нет опции отозвать пакеты (потому что от них зависят другие), а публикация новой версии ничего не изменит».Так или иначе, но
everything
ещё раз напомнил о фундаментальной уязвимости реестра микромодулей с множеством перекрёстных и транзитивных зависимостей. Устанавливая такие зависимости, разработчик частично теряет контроль над своим кодом. Авторы некоторых популярных пакетов npm официально продают их для участия в ботнетах. Например, пакет ua-parser-js
с 7 млн установок продавался за $20 тыс.Каждый месяц из реестра npm удаляется около 300 пакетов по причинам безопасности.
Также продаются и расширения для браузеров, мобильные приложения и десктопные утилиты. Всё это выкладывается на подпольных форумах, а новый владелец инициирует обновление ПО с установкой вредоносного кода на компьютерах тысяч пользователей. Например, сегодня расширение для браузера блокирует рекламу, а завтра оно может установить на компьютер пользователя программу для скрытого майнинга.
В случае с реестром npm ситуация усугубляется множеством транзитивных зависимостей, в которых сложно отслеживать изменения.