Атака на цепочку поставок npm: новый червь распространяется через скрытый механизм сборки node-gyp

security

Экосистема JavaScript снова столкнулась с серьёзной угрозой. Специалисты компании StepSecurity, занимающейся защитой конвейеров разработки, обнаружили активную самовоспроизводящуюся атаку на цепочку поставок, которая распространяется через реестр npm. Под ударом оказались разработчики, использующие как локальные среды, так и автоматизированные конвейеры CI/CD. Особенность этой атаки в том, что она обходит типовые механизмы контроля, встроенные в npm и средства анализа кода.

Описание

Вредоносная программа представляет собой полноценного червя, нацеленного на инфраструктуру непрерывной интеграции и развёртывания. После выполнения в среде разработчика или в конвейере CI она собирает учётные данные из множества сервисов, а затем на их основе публикует заражённые версии других пакетов, которыми владеет жертва. Таким образом вредонос распространяется дальше по экосистеме. Кроме того, червь внедряет вредоносные шаги в рабочие процессы GitHub Actions, чтобы запускаться при каждом новом задании в скомпрометированных репозиториях.

StepSecurity в своём сообщении подчёркивает, что ранее подобных атак в таком масштабе не наблюдалось. Главное отличие - способ доставки вредоносного кода. Традиционные угрозы для цепочки поставок npm используют хуки жизненного цикла в package.json, например preinstall или postinstall. Инструменты безопасности, рецензенты кода и системы аудита npm как раз ориентируются на эти точки. Однако злоумышленник пошёл другим путём.

Он добавляет в пакет небольшой файл binding.gyp. Когда npm встречает такой файл при установке, он автоматически вызывает node-gyp - утилиту для компиляции нативных модулей Node.js. Атакующий использует особенность node-gyp: возможность подстановки команд в массиве sources через конструкцию <!(...). В результате при установке пакета без каких-либо подозрительных записей в package.json выполняется произвольный код. Файл binding.gyp занимает всего около 100 байт, а вызываемый им index.js - от 4,5 до 4,9 мегабайт обфусцированного кода.

Вредоносная программа работает в три этапа. На первом этапе корневой index.js использует шифр Цезаря (ROT-N) для декодирования внутреннего скрипта, который затем расшифровывает две полезные нагрузки, зашифрованные алгоритмом AES-128-GCM (симметричное шифрование с аутентификацией). На втором этапе первая расшифрованная нагрузка беззвучно загружает из GitHub среду выполнения Bun версии 1.3.13 во временную директорию. Это даёт атакующему быструю автономную платформу, которая не оставляет явных следов в дереве процессов Node.js.

Третий этап - основная часть червя, примерно 720 килобайт. Он запускается через загруженную среду Bun и выполняет четыре функции: сбор учётных данных, внедрение в рабочие процессы GitHub Actions, отравление пакетов и эксфильтрацию. При сборе данных червь сканирует переменные окружения в поисках токенов npm, токенов GitHub и персональных ключей доступа (PAT), ключей доступа AWS, учётных данных сервисных аккаунтов GCP, секретов клиентов Azure, токенов HashiCorp Vault, токенов сервисных аккаунтов Kubernetes, ключей API RubyGems, а также паролей из менеджеров 1Password CLI, gopass и pass. Более того, он извлекает маскированные секреты из памяти процессов GitHub Actions runner.

Используя украденные токены GitHub, червь модифицирует файлы рабочих процессов CI/CD в репозиториях, куда жертва может отправлять изменения. Он добавляет шаг установки Bun и шаг выполнения полезной нагрузки, так что червь запускается при каждом новом задании в этих репозиториях. Затем с помощью украденных токенов npm или RubyGems программа запрашивает реестр, загружает все пакеты жертвы, внедряет в них вредоносный код и публикует новые отравленные версии. Именно так червь распространяется от одного скомпрометированного аккаунта на десятки пакетов.

Собранные учётные данные шифруются открытым ключом RSA, жёстко заданным в коде, и отправляются в репозитории, контролируемые злоумышленником, в виде "висячих коммитов" - таких, которые не видны при обычном просмотре веток. Это делает их обнаружение через стандартные интерфейсы GitHub крайне затруднительным.

На момент публикации StepSecurity уже выявила скомпрометированные версии нескольких пакетов в реестре npm, и этот список продолжает расти по мере распространения червя. Разработчикам рекомендуется немедленно проверить свои пакеты на наличие подозрительных файлов binding.gyp, особенно если в них нет соответствующих нативных модулей. Также стоит обратить внимание на необычно большие index.js и несанкционированные изменения в репозиториях. Хотя полное искоренение такой угрозы потребует усилий всего сообщества, знание о механизме атаки - первый шаг к защите.

Индикаторы компрометации

Packages

  • @evolvconsulting/evolv-coder-lite 1.2.0
  • @jagreehal/workflow 1.16.1
  • @vapi-ai/server-sdk 0.11.1, 0.11.2, 1.2.1, 1.2.2
  • ai-sdk-ollama 0.13.1, 1.1.1, 2.2.1, 3.8.5
  • autotel 2.26.4, 3.4.3
  • autotel-adapters 0.3.5
  • autotel-audit 0.1.15
  • autotel-aws 0.13.10
  • autotel-backends 2.12.26
  • autotel-cli 0.8.14
  • autotel-cloudflare 2.18.16
  • autotel-devtools 0.1.1, 1.0.4, 2.1.1, 3.0.2, 4.0.1, 5.1.1, 6.1.2
  • autotel-drizzle 0.0.27
  • autotel-edge 3.16.13
  • autotel-eventcatalog 1.0.1, 2.0.1, 3.0.1, 4.0.2, 5.0.1
  • autotel-hono 0.4.26
  • autotel-mcp 0.1.14, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 13.0.1, 14.0.1, 15.0.2, 16.0.1, 17.0.2, 18.0.1, 19.0.1, 20.0.1, 21.1.1, 22.0.1, 23.0.1, 24.0.1, 25.0.1, 26.0.2, 27.0.1, 28.0.3
  • autotel-mcp-instrumentation 29.0.2, 30.0.5, 31.0.1, 32.0.1, 33.0.2, 34.0.1
  • autotel-mongoose 0.0.3, 1.0.2, 2.0.5, 3.0.1, 4.0.1, 5.0.2, 6.0.1
  • autotel-pact 0.2.2, 1.0.3
  • autotel-playwright 0.4.32
  • autotel-plugins 0.19.26
  • autotel-sentry 0.5.13
  • autotel-subscribers 4.1.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.1.1, 15.0.1, 16.0.2, 17.0.1, 18.0.3, 19.0.1, 20.0.1, 21.0.1, 22.0.2, 23.0.2, 24.0.1, 25.0.1, 26.0.1, 27.0.2, 28.0.2, 29.0.6, 30.0.4, 31.1.4
  • autotel-tanstack 1.13.27
  • autotel-terminal 2.1.1, 3.0.1, 4.0.2, 5.0.1, 6.0.3, 7.0.1, 8.0.1, 9.0.1, 10.0.2, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.2, 16.0.2, 17.0.10, 18.0.4, 19.0.8, 20.0.2, 21.0.1, 22.0.2, 23.0.3
  • autotel-vitest 0.4.26
  • autotel-web 1.12.2
  • awaitly 1.33.3
  • awaitly-analyze 0.24.2, 1.1.1, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1
  • awaitly-libsql 0.1.1, 1.0.1, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.1, 16.0.1, 17.0.1, 18.1.1, 19.0.1, 20.0.1, 21.0.1, 22.0.1
  • awaitly-mongo 0.1.1, 1.0.1, 2.0.1, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.1.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.1, 16.0.1, 17.0.1, 18.0.1, 19.1.1, 20.0.1, 21.0.1, 22.0.1, 23.0.1
  • awaitly-postgres 0.1.1, 1.0.1, 2.0.1, 3.0.2, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.1, 16.0.1, 17.0.1, 18.0.1, 19.1.1, 20.0.1, 21.0.1, 22.0.1, 23.0.1
  • awaitly-visualizer 1.0.1, 2.0.2, 3.0.1, 4.0.1, 5.0.1, 6.0.1, 7.0.1, 8.0.1, 9.0.1, 10.0.1, 11.0.1, 12.0.1, 13.0.1, 14.0.1, 15.0.1, 16.0.1, 17.0.1, 18.1.1, 19.0.1, 20.0.2, 21.0.1, 22.0.2
  • effect-analyzer 0.3.1
  • eslint-plugin-awaitly 0.17.1, 1.0.1
  • eslint-plugin-executable-stories-jest 1.2.1, 2.1.8
  • eslint-plugin-executable-stories-playwright 1.2.1, 2.1.8
  • eslint-plugin-executable-stories-vitest 1.2.1, 2.1.8
  • executable-stories-cypress 3.1.1, 4.0.1, 5.0.1, 6.1.1, 7.0.3, 8.3.2
  • executable-stories-demo 0.1.11
  • executable-stories-formatters 0.11.2
  • executable-stories-init 0.1.2
  • executable-stories-jest 3.1.1, 4.0.1, 5.0.1, 6.1.1, 7.0.3, 8.3.2
  • executable-stories-mcp 0.3.3
  • executable-stories-playwright 3.1.1, 4.0.1, 5.0.1, 6.1.1, 7.0.3, 8.4.3
  • executable-stories-react 0.1.7
  • executable-stories-vitest 2.0.1, 3.1.1, 4.0.1, 5.0.1, 6.1.1, 7.0.3, 8.3.3
  • http-uploader-dev 1.0.7
  • mountly 0.2.2
  • mountly-tailwind 0.1.3
  • node-env-resolver 6.5.1
  • node-env-resolver-aws 9.1.2, 10.0.1, 11.0.1, 12.0.1
  • node-env-resolver-dotenvx 1.0.1, 2.0.1
  • node-env-resolver-nextjs 7.4.2
  • node-env-resolver-vite 2.4.2
  • wrangler-deploy 1.5.5

Комментарии: 0