Атака на npm axios RAT: Атака на npm axios через RAT: как sloppy-joe

Северной Кореи — а США не могли этого сделать 70 лет

Недавно команда Mandiant из Google связала компрометацию npm-пакета axios с группировкой UNC1069, которая ранее была замечена в киберкриминальных действиях, связанных с кражей криптовалюты и атаками на DeFi-платформы. Вредоносный код был похож на WAVESHAPER — C++ бэкдор, который Mandiant ранее приписывал этой же группе

Северная Корея использовала один из самых популярных HTTP-клиентов для JavaScript в своих атаках. Он имеет 100 миллионов загрузок в неделю. Полезная нагрузка: кроссплатформенный RAT (Remote Access Trojan, троян удалённого доступа), который собирает учётные данные, SSH-ключи и облачные токены с каждой машины разработчика, запускающего npm install

Соединённые Штаты на протяжении семи десятилетий потратили триллионы долларов на сдерживание Северной Кореи. Ядерные переговоры, введение санкций, размещение авианосцев, дипломатические усилия и резолюции ООН не сумели помешать КНДР стать одной из наиболее активных киберугроз в мире

Сэндвич sloppy joe останавливает их за 3 секунды

Хронология атаки на npm-пакет axios: что произошло 30 марта

30 марта злоумышленник скомпрометировал npm-аккаунт ведущего мейнтейнера axios (jasonsaayman), используя похищенный токен доступа. Он изменил email аккаунта на адрес Proton Mail и опубликовал две вредоносные версии:

  • axios@1.14.1 — опубликована 31 марта, 00:21 UTC
  • axios@0.30.4 — опубликована 31 марта, 01:00 UTC

Обе версии внедряли новую зависимость: plain-crypto-js@4.2.1. Этот пакет никогда не импортировался нигде в исходном коде axios. Его единственная цель — запустить postinstall-хук (скрипт, выполняемый после установки пакета), который разворачивал платформо-специфичные RAT:

  • macOS: бинарный файл по пути /Library/Caches/com.apple.act.mond, запускаемый через AppleScript
  • Windows: PowerShell RAT с персистентностью через реестр и инъекцией бинарного файла в память
  • Linux: Python RAT-скрипт через nohup

Злоумышленник подготовил plain-crypto-js за 18 часов до атаки и за 39 минут атаковал обе релизные ветки. Это свидетельствует о серьёзной подготовке и детальном планировании, рассчитанном на минимизацию времени реакции сообщества

Как sloppy-joe блокирует каждый уровень этой атаки

Sloppy-joe — это инструмент для обеспечения безопасности цепочки поставок с открытым исходным кодом. Он проверяет ваш package-lock.json, оценивая каждую зависимость по нескольким независимым критериям перед выполнением npm install, не загружая никакие пакеты и не выполняя код

Когда я впервые запустил sloppy-joe на тестовом проекте, меня удивило именно это: инструмент работает как статический анализатор метаданных реестра, а не как антивирус. Никакой сигнатурной базы, никакого облачного агента

Сигнал 1: Ограничение по возрасту версии

ERROR axios [metadata/version-age] Version '1.14.1' of 'axios' was published 0 hours ago
(minimum: 72 hours). New versions need time for the community and security scanners to
review them. Fix: Wait until the version is at least 72 hours old, or pin to an older version.

Скомпрометированные версии были доступны 2–3 часа до того, как npm их отозвал. 72-часовой барьер означает, что они никогда не будут установлены. Точка. Этот механизм не требует никаких знаний об атаке — он работает исключительно на принципе, что новые версии должны пройти проверку сообществом, прежде чем попасть в продакшн

Одна эта проверка останавливает атаку

Но sloppy-joe не ограничивается одним сигналом. При глубоком транзитивном сканировании с флагом --deep пакет plain-crypto-js подвергается пяти независимым проверкам

Сигнал 2: Обнаружение нового пакета

ERROR plain-crypto-js [metadata/new-package] 'plain-crypto-js' was first published 0 days ago.
New packages are higher risk — verify this is a legitimate, maintained project before depending
on it. Fix: Verify 'plain-crypto-js' at its registry page and source repository.

plain-crypto-js был создан за день до атаки. Совершенно новые пакеты в качестве транзитивных зависимостей пакетов со 100 миллионами загрузок изначально подозрительны — это структурная аномалия, которую sloppy-joe фиксирует без каких-либо внешних фидов

Сигнал 3: Опасный install-скрипт — как npm install запускает RAT

ERROR plain-crypto-js [metadata/install-script-risk] 'plain-crypto-js' has install scripts AND
was published 0 days ago and with 0 downloads. Install scripts on new, low-download packages
are the #1 malware delivery vector. Fix: Do not install this package. Verify it is legitimate
before proceeding.

Install-скрипты + новый пакет + ноль загрузок. Это точный отпечаток атаки на цепочку поставок. Сигнал риска install-скрипта в sloppy-joe объединяет несколько слабых сигналов в высоконадёжное обнаружение. Каждая реальная атака на цепочку поставок npm за последние 5 лет соответствовала этому паттерну

Сигнал 4: Отсутствие репозитория с исходным кодом

WARNING plain-crypto-js [metadata/no-repository] 'plain-crypto-js' has no source repository URL
and is a new package (< 30 days old). Legitimate packages almost always link to their source
code. Fix: Verify 'plain-crypto-js' at its registry page.

Легитимные пакеты ссылаются на свой репозиторий GitHub/GitLab. Вредоносные пакеты, созданные как транспортные средства для доставки пейлоада, этим не утруждаются — и это молчание само по себе является сигналом

Сигнал 5: Сходство имени

WARNING plain-crypto-js [similarity/mutation-match] 'plain-crypto-js' is suspiciously similar
to existing package 'crypto-js' Fix: Verify this is the package you intend to use.

plain-crypto-js — явная попытка выглядеть как crypto-js, настоящий популярный криптографический пакет с сотнями миллионов загрузок. Генераторы мутаций sloppy-joe это улавливают: инструмент проверяет не только точные совпадения, но и типичные паттерны typosquatting (подмены имён пакетов)

Пять сигналов. Один сэндвич. Ноль долларов

Вот что примечательно: ни одно из этих обнаружений не требует фидов разведки угроз (threat intelligence feeds), баз данных сигнатур вредоносного ПО или поведенческого анализа на основе ИИ. Все они — вариации одного примитива: перекрёстная проверка того, что код заявляет об использовании, с тем, что реально существует в реестре

  • Версия слишком новая? Пометить.
  • Транзитивная зависимость совершенно новая? Пометить.
  • У нового пакета есть install-скрипты? Заблокировать.
  • Нет репозитория с исходным кодом? Пометить.
  • Имя похоже на популярный пакет? Пометить.

Каждый сигнал по отдельности носит информационный характер. Все пять, срабатывающие одновременно на одном пакете, — это уже достоверность. Именно такая комбинация делает ложноположительные срабатывания редкостью, а реальные атаки — практически неизбежно видимыми

Стоимость этой защиты:

# Добавьте в любой CI-пайплайн

npx sloppy-joe check

UNC1069 потратил 18 часов на подготовку пейлоадов, предварительную сборку RAT для трёх платформ и компрометацию аккаунта мейнтейнера. sloppy-joe обнаруживает это за время, необходимое для чтения package-lock.json

Что sloppy-joe не может обнаружить — и почему это важно знать

Честность важна: sloppy-joe не обнаружил бы саму кражу учётных данных. Злоумышленник захватил аккаунт настоящего мейнтейнера — поле npm _npmUser по-прежнему показывает jasonsaayman. Изменения издателя для обнаружения нет

Аттестация происхождения npm (публикация на основе OIDC через GitHub Actions) — это настоящая защита от кражи токенов: вредоносные версии были опубликованы вручную, в обход CI-пайплайна axios. Это отдельный слой защиты, который sloppy-joe не заменяет

sloppy-joe обнаруживает пейлоад, а не компрометацию. Но именно пейлоад причиняет вам вред — и именно здесь инструмент закрывает брешь, которую не закрывает ни один другой бесплатный механизм в стандартном npm-воркфлоу

Как подключить sloppy-joe к своему проекту

# Установка (единый статический бинарный файл, без зависимостей от среды выполнения)

cargo install sloppy-joe

# Или скачайте проверяемый бинарный архив из GitHub Releases

# https://github.com/brennhill/sloppy-joe/releases

# Проверка текущего проекта — автоматически определяет экосистему по файлам манифеста

sloppy-joe check

Для GitHub Actions достаточно одной строки в воркфлоу:

- uses: brennhill/sloppy-joe-action@v1

sloppy-joe — инструмент безопасности цепочки поставок с открытым исходным кодом, который перехватывает галлюцинированные, typosquatted и скомпрометированные зависимости до того, как они попадут в продакшн. Он запускается до вашего пакетного менеджера, не требует выполнения кода и блокирует атаки типа axios, LiteLLM, event-stream и ua-parser-js

Атака на цепочку поставок LiteLLM (март 2026) скомпрометировала пакет с 97 миллионами ежемесячных загрузок. Злоумышленники похитили учётные данные для публикации, выпустили вредоносные версии, которые собирали SSH-ключи, облачные учётные данные и секреты K8s (Kubernetes)

72-часовой барьер по возрасту версии в sloppy-joe по умолчанию заблокировал бы обе отравленные версии — они были обнаружены в течение нескольких часов, задолго до того, как барьер открылся бы. Если вы запускаете sloppy-joe check в CI, эта атака проваливается

Генераторы кода на основе ИИ галлюцинируют имена пакетов примерно в 20% случаев. Злоумышленники регистрируют эти имена и ждут. sloppy-joe перехватывает их в CI до того, как запустится npm install или pip install

Типичные ошибки при защите цепочки поставок

Я вижу одни и те же паттерны у команд, которые считают, что уже защищены, но на деле оставляют открытые окна. На мой взгляд, самая опасная из них — слепое доверие к npm audit как единственному инструменту

Проверяют только прямые зависимости. Атака axios прошла через транзитивную зависимость — plain-crypto-js никогда не появлялся в package.json проекта напрямую. Без флага --deep или аналогичного механизма транзитивный слой остаётся слепой зоной

Полагаются только на npm audit. npm audit работает с базой известных CVE (Common Vulnerabilities and Exposures, база общеизвестных уязвимостей). Новый вредоносный пакет, созданный 18 часов назад, в этой базе не числится — и audit пройдёт чисто

Не фиксируют версии транзитивных зависимостей. Если package-lock.json не закоммичен или регулярно пересоздаётся без проверки, окно для подмены зависимости остаётся открытым при каждом npm install

Запускают проверки только локально, не в CI. Локальная среда разработчика — не единственное место, где происходит установка зависимостей. Сборочный агент, Docker-образ, деплой-пайплайн — каждый из них является точкой входа

Добавление sloppy-joe check как первого шага в CI закрывает все четыре сценария одновременно, не требуя изменений в остальной инфраструктуре

Частые вопросы о защите цепочки поставок npm

Почему 72 часа — именно такой порог для блокировки новых версий?

Это эмпирически выбранное окно, за которое сообщество и автоматические сканеры успевают проверить новый релиз. Большинство атак на цепочку поставок рассчитаны на первые часы после публикации — именно тогда пакет ещё не попал в базы угроз, но уже активно скачивается через CI-пайплайны. 72 часа перекрывают это окно с запасом

Работает ли sloppy-joe только с npm, или поддерживает другие экосистемы?

Инструмент автоматически определяет экосистему по файлам манифеста в проекте. Упоминание pip install в документации подтверждает поддержку Python-экосистемы. Точный список поддерживаемых менеджеров пакетов доступен в репозитории проекта на GitHub

Может ли sloppy-joe создавать ложноположительные срабатывания на легитимные новые пакеты?

Да, теоретически — если вы намеренно добавляете совершенно новый пакет без репозитория и с install-скриптами. На практике легитимные пакеты почти всегда имеют хотя бы ссылку на репозиторий и несколько загрузок. Комбинация пяти сигналов одновременно на одном пакете встречается у реальных атак, а не у добросовестных новых библиотек

Заменяет ли sloppy-joe npm audit или Dependabot?

Нет, и это не цель инструмента. npm audit и Dependabot работают с базами известных уязвимостей — они закрывают угрозы, которые уже задокументированы. sloppy-joe закрывает угрозы нулевого дня в цепочке поставок: новые вредоносные пакеты, typosquatting и slopsquatting (подмена имён, галлюцинированных ИИ-генераторами кода). Оба слоя нужны одновременно

Нужно ли менять структуру проекта или CI-пайплайна для интеграции?

Нет. Достаточно добавить один шаг перед установкой зависимостей: npx sloppy-joe check или - uses: brennhill/sloppy-joe-action@v1 в GitHub Actions. Инструмент читает существующий package-lock.json и не требует изменений в остальной конфигурации

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x