Атаки на цепочку поставок npm: как заражают сборку через чужие пакеты

Безопасность

Атаки на цепочку поставок npm: как заражают сборку через чужие пакеты

Установили пакет из npm, а вместе с ним, возможно, впустили в сборку чужой код. За 2026 год атаки на цепочку поставок в npm перестали быть редкими инцидентами и превратились в поток. Захватывают уже не безвестные библиотеки, а пакеты с сотнями миллионов загрузок в неделю, а новые версии заражают сами себя, воруя токены сопровождающих. Для команды, которая пишет на JavaScript или собирает фронтенд, вывод один: ваша сборка настолько безопасна, насколько безопасен самый мелкий транзитивный пакет в дереве зависимостей.

Что происходит в npm

Схема атаки сместилась с «подсунуть свой вредоносный пакет» на «угнать чужой популярный». Классический пример этого года — пакеты keyv и cacheable, перехваченные через компрометацию учётной записи сопровождающего. Раньше был случай с node-ipc: 14 мая в реестр разом опубликовали три вредоносные версии, и каждая несла одинаковый обфусцированный стилер учётных данных весом около 80 КБ. А в конце марта атаковали axios, библиотеку примерно со ста миллионами загрузок в неделю; вредоносные версии провисели около трёх часов, и этого хватило, чтобы Google приписал компрометацию северокорейской группе.

Отдельно стоит выделить самораспространяющиеся черви. Схема у них замкнутая: троянская версия крадёт npm- или GitHub-токен сопровождающего, публикует от его имени заражённые версии его пакетов, а украденными правами заражает следующее пространство имён. С момента червя Shai-Hulud осенью 2025 года частота и техническая глубина таких атак заметно выросли: единичные случаи превратились в системные кампании, которые прицельно эксплуатируют доверие внутри экосистемы. Часть заражённых пакетов в этих волнах имела более 150 миллионов загрузок в неделю, то есть попадала в сборки десятков тысяч компаний одновременно.

ИнцидентЧто произошлоМасштаб
keyv и cacheableзахват через учётку сопровождающегопопулярные утилиты кэширования
node-ipcтри вредоносные версии со стилером~80 КБ обфусцированного пейлоада
axiosподмена версий на ~3 часа~100 млн загрузок в неделю
черви (после Shai-Hulud)кража токена и самораспространениесотни пакетов за одну кампанию
Свежие атаки на цепочку поставок в npm за 2026 год

Как выглядит заражение на практике

Механика проще, чем кажется. У npm-пакета есть скрипты жизненного цикла, например postinstall, которые выполняются автоматически при установке. Разработчику достаточно одной команды установки зависимостей, и код из пакета уже работает на его машине с его правами. Вредоносный пакет этим и пользуется: в момент установки он читает переменные окружения, файлы конфигурации, ключи в домашнем каталоге и токены, а затем тихо отправляет их на сервер злоумышленника.

Дальше всё зависит от того, где именно сработал install-скрипт. На ноутбуке разработчика утекут его личные токены и доступы. Но по-настоящему больно, когда установка идёт в конвейере сборки. Туда стекаются самые ценные секреты проекта: ключи к облаку, токены публикации в реестры, доступы к продакшену. Компрометация одной зависимости в этот момент превращается из локальной неприятности в захват всей цепочки поставки. Именно так работают крупные атаки: не ломают вас в лоб, а въезжают через доверенный компонент, которому вы сами дали зелёный свет.

Почему lock-файла недостаточно

Многие считают, что зафиксированный lock-файл решает проблему, но это лишь часть защиты. Он фиксирует версии и хеши, и это действительно спасает от случайной подмены. Но когда сопровождающий сам скомпрометирован и публикует новую «легитимную» версию, обновление подтянет именно её, а вместе с обновлением приедет и вредоносный код. Здесь помогает не автоматика, а дисциплина: обновляться осознанно, читать список изменений, не гнаться за самой свежей версией в тот же час, когда она вышла.

Вторая проблема — транзитивные зависимости. Вы подключили десяток пакетов, а притащили за собой сотни. Их вы не выбирали и не проверяли, но выполняются они с теми же правами. Поэтому важно видеть всё дерево целиком, а не только прямые зависимости, и понимать, какие из них вообще запускают код при установке. История помнит и event-stream в 2018 году, и ua-parser-js в 2021-м, так что проблема не нова, но с приходом самораспространяющихся червей она вышла на новый масштаб.

Чем это грозит вашим клиентам

Есть и второй круг последствий, о котором думают реже. Если заражённая зависимость попала в ваш продукт, вы становитесь не жертвой, а переносчиком: вредоносный код уезжает вашим клиентам вместе с очередным релизом. Именно так работают самые громкие атаки на цепочку поставок: злоумышленник ломает одного поставщика, чтобы дотянуться до сотен его клиентов сразу. Для аутсорсинговой команды или продуктовой компании это прямой репутационный и юридический риск, ведь вы отвечаете за то, что поставили, даже если сами стали жертвой чужой уязвимости.

Отсюда практический вывод про прозрачность. Стоит вести перечень компонентов, из которых собран ваш продукт (так называемый SBOM), чтобы в случае инцидента за минуты ответить на вопрос, есть ли у вас этот заражённый пакет и где именно. Без такого перечня разбор превращается в панические поиски вручную по десяткам репозиториев, пока злоумышленник спокойно пользуется добытым. Полезно заранее проговорить с командой и сам сценарий: что мы делаем, если завтра выяснится, что одна из зависимостей была заражена неделю назад, кто ротирует секреты, кто уведомляет клиентов, как быстро выкатываем чистую сборку. Отрепетированный ответ отличает контролируемый инцидент от аврала.

Даже небольшая команда в зоне риска

И это не проблема только крупных проектов. Небольшая команда часто даже уязвимее: у неё меньше ресурсов на проверку зависимостей, а один разработчик нередко совмещает и разработку, и деплой, и управление секретами. Достаточно, чтобы его рабочая машина оказалась заражена через install-скрипт, и под угрозой сразу весь проект вместе с клиентами. Масштаб бедствия тут определяется не размером компании, а тем, к скольким системам имеет доступ скомпрометированная учётка.

Как защищаться

Полностью отказаться от чужого кода нельзя, но риск можно сжать до управляемого. Практический минимум для команды:

  • Фиксировать зависимости через lock-файлы и точные версии, а обновления проводить осознанно, с проверкой изменений, а не подтягивать «свежак» автоматически.
  • Отключать или строго ограничивать install-скрипты, проверять новые и обновлённые зависимости на аномалии, держать под контролем всё дерево транзитивных пакетов.
  • Минимизировать права конвейеров сборки: короткоживущие токены, секреты не в коде, отдельные ограниченные учётки для публикации, обязательная двухфакторная аутентификация у сопровождающих.
  • Регулярно проверять сам код и его окружение — это задача аудита исходного кода и пентеста веб-приложений, а общую защищённость закрывает тестирование на проникновение.

Вывод

Атаки на npm напоминают, что периметр современного приложения проходит не по вашему серверу, а по вашему package.json. Доверие к экосистеме превратили в оружие, и один угнанный токен сопровождающего способен заразить пакеты с миллионами загрузок. Разбирайтесь, что именно вы тянете в сборку, ограничивайте права конвейеров и проверяйте зависимости так, будто среди них уже есть заражённый. Мы в HirexTech помогаем выстроить этот контроль, а полезный разбор методик и цен на тестирование можно посмотреть и у наших коллег из SecurityLab.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх