Каждый npm install — это решение довериться чужому коду. Вот как сделать этот выбор осознанным: от метаданных пакета до подтверждения происхождения, скриптов установки и инструментов аудита.
Если кратко: Не доверяйте npm пакетам вслепую. Проверяйте дату публикации, скрипты установки (npm view), еженедельные загрузки, размер бандла (npm pack --dry-run), состояние GitHub и запускайте npm audit. Используйте npm install --allow-scripts=pkg1,pkg2 с npm 11.16+, чтобы скрипты установки были опциональными. Атака Mini Shai-Hulud (май 2026) — свежий пример того, что может пойти не так — подробнее в моём разборе атаки Shai-Hulud.
Каждый раз, когда вы запускаете npm install <пакет>, вы предоставляете коду этого пакета — и всем транзитивным зависимостям, которые он тянет за собой — полный доступ к вашей машине, сборочному серверу и, потенциально, к production-окружению. Экосистема npm построена на доверии, и именно доверие атакующие эксплуатируют в первую очередь.
Атака Mini Shai-Hulud в мае 2026 скомпрометировала более 170 пакетов, включая TanStack, Mistral AI и UiPath. Злоумышленники получили доступ через взлом аккаунтов мейнтейнеров и использовали postinstall-скрипты для кражи учётных данных и внедрения вредоносного кода в production-сборки. Это была не теоретическая угроза — атака затронула реальные компании с собственными отделами безопасности.
Инцидент с бэкдором Red Hat Shai-Hulud в npm-пакетах стал ещё одним тревожным сигналом. Обе атаки объединяет общий паттерн: злоумышленники нацеливались на популярные пакеты с низким контролем со стороны мейнтейнеров, использовали скрипты установки как вектор атаки и полагались на то, что большинство разработчиков никогда не смотрят, что именно выполняется во время npm install.
Хорошая новость: npm 11.16.0 представил флаг --allow-scripts, делающий скрипты установки опциональными по умолчанию. Экосистема движется к более безопасным настройкам, но ни один флаг CLI не заменяет экспертную оценку разработчика. Это руководство проведёт вас по каждому сигналу, который стоит оценить перед добавлением зависимости в проект.
Пакет с 50 000 звёзд на GitHub может быть заброшен три года назад. Звёзды измеряют популярность, а не качество или безопасность. Вот метрики, которые действительно коррелируют с качественным обслуживанием пакета.
Самый важный сигнал. Проверьте, когда пакет последний раз публиковался в npm:
npm view <пакет> time --json | tail -5
Для активно поддерживаемых пакетов ожидайте публикацию в течение последних 6 месяцев. Пакеты, не обновлявшиеся 2+ года — серьёзный красный флаг. Они содержат известные CVE, не поддерживают современные версии Node.js и не получат патчи безопасности при обнаружении новых уязвимостей.
Еженедельные загрузки показывают уровень принятия пакета сообществом. Пакет со 100 000+ загрузок в неделю проверен тысячами проектов в реальных условиях. Однако количество загрузок может быть завышено CI/CD-системами, которые переустанавливают пакеты при каждом запуске пайплайна. Перепроверьте через количество зависимых пакетов:
npm view <пакет> dependents
npm view <пакет> description version downloads
Большое количество зависимых пакетов означает, что другие авторы доверяют API настолько, чтобы строить на нём свои решения — это более сильный сигнал, чем просто количество загрузок.
Неожиданно большой пакет может делать больше, чем вам нужно — или содержать ненужные зависимости. Проверьте распакованный размер и количество файлов:
npm view <пакет> --json | grep -E "dist|unpackedSize"
Для визуальной проверки используйте npm pack <пакет> --dry-run — он покажет каждый файл, который будет установлен. Если простая утилита поставляет 50+ файлов, стоит спросить «зачем».
Совет: Используйте bundlephobia.com для проверки размера в минифицированном и сжатом виде перед установкой. Пакет, который выглядит небольшим в node_modules, может оказаться тяжёлым для клиентского JS-бандла.
Жизненные скрипты npm (preinstall, postinstall, preuninstall) — это shell-скрипты, выполняющиеся с вашими правами пользователя во время npm install. Они могут читать переменные окружения, обращаться к файловой системе, делать сетевые запросы и устанавливать дополнительное ПО. Это вектор атаки №1 в supply chain-атаках.
# Проверка наличия жизненных скриптов
npm view <пакет> scripts
# Просмотр всех файлов пакета без установки
npm pack <пакет> --dry-run
Если поле scripts содержит postinstall без очевидного node build.js или JS-цели, проверьте подробнее. Нативные модули (node-gyp rebuild) — легитимная причина для postinstall-скриптов, но любой скрипт, загружающий внешние ресурсы или обращающийся к сети, подозрителен и требует верификации.
--allow-scriptsnpm 11.16.0 представил важное улучшение безопасности: флаг --allow-scripts делает скрипты установки опциональными по умолчанию. Вместо автоматического выполнения всех postinstall-скриптов, только явно одобренные пакеты могут их запускать:
# Установка с опциональными скриптами (npm 11.16+)
npm install <пакет> --allow-scripts=<пакет>
Это одно изменение блокирует самый распространённый вектор supply chain-атак — скомпрометированный пакет, который тихо добавляет вредоносный postinstall-скрипт. Подробнее о том, как развивался этот RFC и какие альтернативы существуют для авторов пакетов, читайте в моём анализе RFC npm install scripts opt-in.
Подтверждение происхождения (provenance attestation) — это ответ npm на вопрос «был ли этот пакет действительно опубликован его мейнтейнером из реального исходного кода?». Используются логи прозрачности Sigstore и SLSA Build Level 2+ для криптографической привязки опубликованного пакета к конкретной CI-сборке.
Когда пакет имеет подтверждение происхождения, вы можете проверить, что он был собран на GitHub Actions (или другой поддерживаемой CI-системе) из конкретного коммита репозитория:
# Проверка подтверждения происхождения
npm view <пакет> --json | jq '.dist.attestations'
# Верификация при установке
npm install <пакет> --verify-provenance
Не все пакеты публикуют подтверждение происхождения — для этого требуется явная настройка CI и OIDC-токен GitHub. Но крупные фреймворки и инструменты постепенно внедряют эту практику. Когда доступно, предпочитайте пакеты с подтверждением происхождения, особенно для критической инфраструктуры: сборочных инструментов, бандлеров и библиотек безопасности.
Репозиторий пакета на GitHub расскажет вам больше, чем страница на npm. Вот что стоит проверить, прежде чем доверять пакету ваше production-окружение.
Здоровый проект имеет коммиты за последние 3-6 месяцев. Проверьте ритм: коммиты регулярны или появляются всплесками перед релизами? Всплески активности, за которыми следуют долгие периоды тишины, часто означают обновления, продиктованные форсированием зависимостей, а не активной поддержкой.
Перейдите на вкладку Issues GitHub и отфильтруйте по «Most commented». Проект с 200 открытыми issues и без ответов от мейнтейнеров — мёртвый проект. У здоровых проектов время ответа на issues не превышает 7 дней, и они активно закрывают устаревшие тикеты.
README без бейджей CI — красный флаг. Ищите бейджи GitHub Actions, CircleCI или других систем сборки. Также проверьте покрытие кода, линтинг и сканирование безопасности в CI-пайплайне. Проект, который не запускает тесты перед слиянием PR, неизбежно поставляет баги.
Фактор автобуса (bus factor) имеет значение. Проект с одним мейнтейнером, который не заглядывал в репозиторий 8 месяцев — это единая точка отказа. Проекты с несколькими мейнтейнерами (3+) из разных организаций лучше защищены от этой проблемы и обычно быстрее обрабатывают issues.
Ни один инструмент не ловит всё. Лучшая стратегия безопасности зависимостей комбинирует несколько подходов к сканированию.
| Инструмент | Что проверяет | Сильные стороны | Когда использовать |
|---|---|---|---|
| npm audit | Известные CVE по базе npm advisory | Встроенный, без настройки, данные от Snyk | Каждая установка, каждый CI запуск |
| Socket.dev | Сигналы безопасности и качества (скрипты установки, typosquatting, сетевой доступ, подозрительные паттерны) | Обнаруживает supply chain риски без CVE, PR-бот для новых зависимостей | PR review, оценка нового пакета |
| Snyk | Известные уязвимости с рекомендациями по исправлению | Широкая база, интеграция со сканированием контейнеров, проверка лицензий | CI пайплайн, ежемесячный глубокий аудит |
| OpenSSF Scorecard | Практики безопасности open-source проекта (CI тесты, SAST, права токенов, поддержка) | Проверяет сам процесс разработки пакета | Перед выбором нового критического пакета |
| npm query | Структура и состав дерева зависимостей | SQL-подобные запросы к node_modules, поиск пакетов со скриптами, устаревших и дублирующихся | Аудит дерева зависимостей, проверка после установки |
# CI пайплайн (остановка при критических)
npm audit --audit-level=critical
# Socket.dev CLI сканирование
npx socket scan
# Поиск всех пакетов со скриптами установки
npm query ".scripts:not(.scripts == {})"
# Поиск устаревших пакетов
npm query ".deprecated"
Команда npm query особенно полезна — она использует CSS-подобные селекторы для поиска в дереве зависимостей:
# Пакеты с postinstall скриптами
npm query ":attr(.scripts, [postinstall])"
Пакеты не остаются здоровыми навсегда. Следите за этими сигналами устаревания в ваших текущих зависимостях:
Когда вы обнаруживаете устаревающий пакет, планируйте миграцию. Не ждите критической CVE, которая вынудит вас действовать в спешке. Лучшее время для замены неподдерживаемого пакета — когда у вас есть время тщательно оценить альтернативы.
Одна прямая зависимость часто тянет за собой десятки транзитивных. Та утилита, которую вы добавили ради одной функции? Она может притащить 50 пакетов.
# Полное дерево
npm ls --all
# Только production зависимости
npm ls --all --prod
# Почему конкретный пакет в проекте
npm ls <имя-пакета>
Для больших проектов npm ls --all может быть перегружен. Используйте npm ls <пакет> чтобы отследить, какая именно прямая зависимость притянула конкретный пакет.
Всегда проверяйте, нужна ли вам зависимость в production. Инструменты вроде webpack, typescript и eslint должны быть только в devDependencies. Помещение их в dependencies раздувает production node_modules и увеличивает поверхность атаки.
# Подсчёт пакетов по категориям
npm ls --prod | wc -l
npm ls --dev | wc -l
Если количество production-зависимостей более чем в 10 раз превышает количество прямых зависимостей, ваше дерево зависимостей имеет избыточную глубину — рассмотрите npm dedupe или монорепозиторий с общими пакетами.
Перед добавлением любого нового npm пакета в проект пройдитесь по этому чеклисту. Это занимает 2-3 минуты на пакет и не раз спасало от добавления заброшенных, раздутых или подозрительных пакетов.
npm installnpm view <пакет> time — в пределах 6 месяцев?npm view <пакет> scripts — есть postinstall?npm view <пакет> downloads — 1 000+?npm view <пакет> license — MIT, Apache-2.0 или совместимая?npm pack <пакет> --dry-run — разумное количество файлов?npm view <пакет> --json | grep attestationsДля пакетов, на которые будет полагаться вся команда (фреймворки, бандлеры, управление состоянием, библиотеки безопасности), уделите дополнительные 10 минут: внимательно прочитайте README, проверьте скорость ответа на issues, просмотрите последние 10 коммитов и проверьте, проходил ли пакет аудит третьей стороной.
Совместимость лицензий важна больше, чем большинство разработчиков осознают. Лицензия вашего проекта должна быть совместима с лицензией каждой зависимости. Самый частый конфликт — GPL-пакеты в проприетарном ПО: copyleft-положения GPL могут вынудить вас открыть всё приложение.
# Проверка лицензии пакета
npm view <пакет> license
# Список лицензий всех пакетов
npm licenses
# Или с license-checker для JSON вывода
npx license-checker --json
Безопасные варианты для коммерческих проектов: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, Unlicense. Используйте эти лицензии как критерий приёма пакета, если у вас нет юридического отдела для проверки каждой зависимости.
Давайте посмотрим на практический пример. Вы оцениваете zod для валидации схем. Вот что говорят сигналы:
Вот как выглядит доверенный пакет по всем измерениям. Когда пакет не проходит два или более из этих пунктов — стоит спросить, действительно ли он вам нужен, или существует более простая альтернатива.
npm audit после установки.--allow-scripts для блокировки этого вектора. Подробнее об атаке — в моём разборе Shai-Hulud.npm view <пакет> scripts — команда покажет все жизненные скрипты. Также можно просмотреть содержимое пакета через npm pack <пакет> --dry-run, который выводит все файлы без скачивания. Для просмотра содержимого скриптов распакуйте package.json пакета.npm audit (встроенный, сканирование CVE), Socket.dev (обнаружение supply chain рисков, скрипты установки, typosquatting), Snyk (широкая база уязвимостей с рекомендациями по исправлению), OpenSSF Scorecard (оценка практик безопасности проекта) и npm query (анализ дерева зависимостей). Используйте их в комбинации — ни один инструмент не покрывает все риски.npm audit при каждой установке и в CI пайплайне (с остановкой при критических уязвимостях). Полный обзор зависимостей проводите не реже раза в месяц — проверяйте устаревшие пакеты, новые CVE и разбухание дерева зависимостей. Крупные обновления версий — естественный повод для переоценки. RFC npm с опциональными скриптами установки — хороший пример эволюции экосистемы — подробнее в моём анализе RFC.Оценка npm-пакетов — лишь часть построения безопасных и поддерживаемых веб-приложений. Каждый мой проект строится по структурированному подходу к управлению зависимостями, аудиту безопасности и долгосрочному обслуживанию. Если вы планируете новый проект или хотите улучшить существующий, свяжитесь со мной для бесплатной консультации.
Я — full-stack разработчик с более чем 20-летним опытом создания production-приложений на React, Vue, Node.js и других технологиях. Живу в Минске, работаю по всему миру — обсудим ваш проект.
Расскажите о вашем проекте — я оценю ваш технологический стек и предоставлю предварительную смету. Бесплатно.