Аудит npm-зависимостей: что делать с уязвимыми пакетами
Команда npm audit может найти уязвимость, но не решает, можно ли безопасно обновить пакет. Разбираем, как читать отчёт, отличать прямую зависимость от транзитивной и не сломать проект поспешным npm audit fix.

Одна команда npm audit может показать десятки уязвимостей, хотя в вашем коде не используется ни одна опасная функция пакета. Проблема в другом: отчёт связывает уязвимый диапазон версий с конкретным деревом зависимостей, а исправление иногда требует обновить мажорную версию, заменить библиотеку или принять временный риск. Ниже — практический порядок для проектов на Node.js 22.x и npm 10.x: от чистого отчёта до решения, которое можно объяснить команде и зафиксировать в CI.
Сначала зафиксируйте состояние проекта
Аудит имеет смысл только для воспроизводимого набора пакетов. Перед проверкой сохраните текущую ветку, закоммитьте изменения и убедитесь, что рядом с package.json лежит актуальный package-lock.json. Без lock-файла вы проверяете не установленное дерево, а набор ограничений версий, который может разрешиться иначе на другой машине.
Для первого запуска используйте npm 10.x. Версию можно проверить так:
node --version
npm --version
npm audit
Команда завершится кодом 0, если npm не нашёл уязвимостей в проверяемом дереве, и ненулевым кодом, если отчёт содержит проблемы. Для CI это важно: сборка может остановиться ещё до запуска тестов.
Транзитивная зависимость — пакет, который добавлен не напрямую вами, а через другую библиотеку. Например, приложение зависит от web-framework, а тот подтягивает уязвимый parser. Такой пакет не всегда можно обновить обычным изменением строки в вашем package.json.
Как читать вывод npm audit
Не начинайте с числа уязвимостей. Найдите для каждой записи четыре вещи: имя пакета, диапазон уязвимых версий, уровень серьёзности и цепочку, по которой пакет попал в проект. Особое внимание уделите полю с исправленной версией и пометке, требуется ли breaking change.
- Прямая зависимость. Пакет указан в вашем
package.json. Обновление контролируете вы, но изменение API может потребовать правок в исходном коде. - Транзитивная зависимость. Пакет пришёл через другую библиотеку. Сначала ищите обновление родительского пакета.
- Dev-зависимость. Она нужна для сборки, тестов или линтеров. Риск не исчезает, но отличается от уязвимости в пакете, который попадает в production-образ.
- Нет исправленной версии. Обновить lock-файл недостаточно. Придётся заменить пакет, убрать функцию или принять риск с документированным сроком пересмотра.
Чтобы понять, почему пакет установлен, используйте:
npm explain имя-пакета
npm ls имя-пакета --all
npm explain показывает цепочку зависимости, а npm ls помогает увидеть фактически установленные версии и дубли. Подставьте настоящее имя пакета без угловых скобок.
Хороший результат аудита — не ноль строк любой ценой, а понятный список рисков: что исправить сейчас, что проверить вручную и почему оставшийся пакет пока не обновляется.
Три способа исправить уязвимость
1. Обновить зависимость в разрешённом диапазоне
Это самый безопасный вариант, если исправление находится в текущем semver-диапазоне*. Сначала измените только lock-файл и посмотрите разницу:
npm audit fix --package-lock-only
git diff -- package-lock.json
npm ci
npm test
npm audit
Если тесты проходят, проверьте изменения в lock-файле и закоммитьте их вместе с результатом проверки. Такой порядок не меняет package.json и не расширяет заявленные диапазоны версий.
2. Обновить прямую зависимость вручную
Если npm указывает на новую мажорную версию, не запускайте npm audit fix --force вслепую. Сначала изучите changelog и migration guide пакета, затем обновите зависимость обычной командой npm и прогоните тесты, сборку и ручной сценарий, на котором используется этот пакет.
npm install имя-пакета@версия-с-исправлением
npm test
npm run build
npm audit
Точную версию подставляйте из отчёта npm или официального релиза пакета. Запись вида версия-с-исправлением — обозначение места, а не готовое значение.
3. Обновить родительский пакет или временно заменить зависимость
Для транзитивной зависимости сначала найдите пакет верхнего уровня через npm explain. Часто исправление приходит в новой версии именно этой библиотеки. Если поддержка прекращена или исправленной версии нет, сравните замену по API, размеру production-дерева, лицензии и покрытию тестами.
| Подход | Когда выбирать | Цена и риск |
|---|---|---|
| Обновление lock-файла | Исправление совместимо с текущим диапазоном | Минимальные изменения, но нужно проверить дубли и тесты |
| Обновление прямого пакета | Исправление только в новой версии | Возможны изменения API и поведения |
| Обновление родительской зависимости | Уязвимый пакет транзитивный | Меняется более крупный участок дерева |
| Замена или удаление | Исправления нет или пакет заброшен | Стоимость миграции и риск новых дефектов |
* Semver — соглашение о нумерации версий, где изменения в major, minor и patch обычно обозначают разный уровень совместимости. Это не гарантия: конкретный пакет может нарушать совместимость даже при формальном соблюдении схемы.
Почему npm audit fix не закрывает задачу
Автоматическое исправление работает только там, где npm может выбрать совместимую версию и не нарушить ограничения дерева. Команда не знает, что ваш код зависит от неочевидного поведения библиотеки, и не заменяет тестирование. Кроме того, наличие advisory не означает, что уязвимый путь реально достижим из вашего приложения, но и отсутствие срабатывания не доказывает безопасность собственного кода.
Не путайте три проверки:
- Аудит зависимостей сопоставляет версии пакетов с опубликованными предупреждениями.
- Тесты проверяют, что после обновления приложение продолжает работать.
- Ревью кода и настройки production показывают, можно ли добраться до опасного сценария через HTTP, очередь, CLI или другой вход.
Что ломается на практике
В отчёте написано «No fix available»
Проверьте страницу advisory, цепочку через npm explain и дату последнего релиза родительского пакета. Если исправления действительно нет, зафиксируйте затронутую функцию, способ эксплуатации и компенсирующую меру: отключение входного сценария, валидацию данных, ограничение доступа или замену библиотеки. Не помечайте проблему закрытой только потому, что она не обновляется.
После обновления появился ERESOLVE
npm ERR! code ERESOLVE означает, что npm не смог согласовать peer-зависимости. Не начинайте с --legacy-peer-deps: этот флаг может скрыть несовместимое дерево. Найдите конфликтующие пакеты в выводе, обновите их согласованной парой и проверьте проект на чистой установке через npm ci.
Локально всё работает, а CI падает
Сравните версии Node.js, npm и содержимое lock-файла. В CI устанавливайте зависимости командой npm ci, а не npm install: она предназначена для чистой установки по lock-файлу и выявляет рассинхронизацию между манифестом и зафиксированным деревом.
Уязвимость только в dev-зависимости
Не удаляйте её автоматически из отчёта. Проверьте, попадает ли пакет в production-образ и запускаются ли его скрипты в сборочном окружении. Если production устанавливается без dev-пакетов, это снижает конкретный риск, но не отменяет обновление инструментов сборки.
Когда и как запускать аудит в CI
Для pull request достаточно запускать аудит на lock-файле и останавливать сборку на согласованном уровне риска. На первом этапе не блокируйте весь проект из-за каждой записи: разделите политику по production- и dev-зависимостям, срокам исправления и наличию эксплуатируемого пути.
npm ci
npm audit --audit-level=high
npm test
Порог --audit-level=high меняет код завершения команды, но не превращает средние и низкие проблемы в безопасные. Порог выбирайте вместе с владельцем продукта: важны тип приложения, доступность пакета из внешней сети и цена простоя сборки.
Храните в задаче не только скриншот отчёта, а имя пакета, установленную версию, исправленную версию, цепочку зависимости, владельца и дату повторной проверки. Так аудит становится процессом, а не разовой реакцией на красную строку.
Что делать дальше
Настройте чистую установку через npm ci, добавьте аудит в CI и начните с инвентаризации production-дерева. Для каждой уязвимости измеряйте не только количество записей, но и время до исправления, число повторяющихся пакетов и долю проблем без доступного обновления. Следующим шагом будет отдельный разбор содержимого production-образа: он показывает, какие зависимости действительно доезжают до работающего сервиса.
Инфографика для маркетплейса: Три главных преимущества товара короткими фразами, выноски в безопасной зоне превью, точный размер площадки.
Спросить за 60 ₽Источники: npm Docs: Auditing package dependencies for security vulnerabilities, npm Docs: npm audit
Частые вопросы
Нужно ли исправлять все уязвимости из npm audit?
Можно ли сразу выполнить npm audit fix --force?
Почему npm audit показывает уязвимость, которой нет в моём коде?
Что делать, если npm audit сообщает No fix available?
Нужно ли запускать npm audit после каждой установки?
Что делать, если после обновления npm появился ERESOLVE?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.