Массовая атака на экосистему npm: 141 вредоносный пакет Mastra с кражей криптокошельков и данных браузера

security

17 июня 2026 года специалисты компании Socket зафиксировали масштабную атаку на цепочку поставок программного обеспечения, затронувшую пакеты из пространства имён @mastra. Злоумышленник, действовавший через учётную запись npm ehindero, в течение короткого промежутка времени опубликовал 141 вредоносную версию пакетов Mastra. Атака представляет серьёзную угрозу для тысяч проектов, поскольку основная библиотека @mastra/core загружается более 918 тысяч раз в неделю. Жертвами могут стать разработчики, использующие Mastra в своих приложениях, а также сборочные конвейеры CI/CD.

Описание

Сам по себе код опубликованных пакетов @mastra/* не содержал изменений - он остался идентичным последней легитимной сборке. Вредоносная функция была внедрена через транзитивную зависимость. В каждый манифест package.json была добавлена строка с зависимостью от пакета easy-day-js, который представляет собой typosquatting (имитацию) популярной библиотеки dayjs. Пакет easy-day-js был опубликован днём ранее, 16 июня, с другого аккаунта (sergey2016). Версия 1.11.21 была чистой, а версия 1.11.22 содержала вредоносный сценарий postinstall, который запускался автоматически при выполнении команды npm install. Таким образом, любой разработчик, установивший одну из скомпрометированных версий @mastra/*, немедленно загружал и исполнял вредоносное ПО.

Согласно анализу исследователей Socket, загрузчик, написанный на Node.js и обфусцированный с помощью obfuscator.io, выполнял следующие действия. Сначала он отключал проверку сертификатов TLS (параметр NODE_TLS_REJECT_UNAUTHORIZED = 0), затем отправлял на сервер управления метку жертвы, записывая имя текущего каталога во временный файл .pkg_history. После этого он загружал второй этап (полезную нагрузку) с адреса 23.254.164.92:8000, сохранял её в случайный файл в папке TEMP и запускал как фоновый процесс, передавая ему адрес другого сервера для эксфильтрации данных. Сам загрузчик удалял себя, затрудняя криминалистический анализ.

Второй этап представлял собой кросс-платформенный имплант размером около 41 КБ, который не ограничивался простым сбором данных, а создавал механизмы закрепления в системе. Он распространялся на три основные операционные системы. На Windows он добавлял значение реестра NvmProtocal в автозагрузку текущего пользователя, скрываясь в каталоге C:\ProgramData\NodePackages\ с именами protocal.cjs и config.json. На macOS создавал агент запуска LaunchAgent с меткой com.nvm.protocal, который выполнял скрипт из ~/Library/NodePackages/protocal.cjs. На Linux устанавливал systemd-модуль пользовательского уровня ~/.config/systemd/user/nvmconf.service, запускавший тот же скрипт. Все эти имена маскировались под легитимные инструменты управления Node.js (NVM), чтобы не вызывать подозрений у разработчиков.

После установки закрепления имплант отправлял на сервер управления стартовый маяк, содержащий информацию о системе (имя хоста, архитектура, платформа, список процессов и установленных приложений). Затем он переходил в цикл опроса, ожидая команд от оператора. Сервер мог вернуть произвольный код для выполнения через встроенные раннеры (Node.js или Shell). Это означало, что атакующие имели возможность в любой момент доставить на скомпрометированную машину дополнительные модули, в том числе для кражи паролей, криптовалютных ключей или других конфиденциальных данных.

В текущей версии имплант уже собирал историю браузера (Chrome, Edge, Brave) путём копирования и чтения SQLite-файла History, а также инвентаризировал установленные расширения криптовалютных кошельков. Он содержал жёстко заданный список из 166 идентификаторов расширений, включая MetaMask, Phantom, Coinbase Wallet, Binance Wallet, TronLink и другие. Имплант проверял, какие из этих расширений присутствуют в профилях браузеров, и отправлял на сервер их идентификаторы и пути. Однако в обнаруженном образце он не копировал данные самих кошельков (базы LevelDB), а только составлял перечень. Тем не менее из-за возможности динамической доставки команд угроза кражи средств остаётся высокой.

Эксфильтрация осуществлялась по протоколу HTTPS с использованием поддельного User-Agent, маскирующего трафик под устаревший браузер Internet Explorer 8. Для шифрования использовался самоподписанный сертификат - обе стадии отключали проверку TLS, что позволяло злоумышленникам использовать любой сертификат без риска блокировки сертификационными центрами.

Socket зафиксировал вредоносный пакет easy-day-js версии 1.11.22 уже через шесть минут после его публикации. Пользователи Socket были автоматически защищены: установка скомпрометированных версий блокировалась до выполнения postinstall-сценария. Компания опубликовала полный список затронутых пакетов и версий на специальной странице кампании.

Любая система, на которой была выполнена установка одной из вредоносных версий @mastra/*, должна считаться потенциально скомпрометированной. Поскольку полезная нагрузка запускалась уже на этапе npm install, уязвимыми оказались не только рабочие станции разработчиков, но и сборочные серверы, агенты CI/CD и любые окружения, где выполнялась автоматическая установка зависимостей. Разработчикам, которые используют Mastra, рекомендуется немедленно проверить наличие пакета easy-day-js в lock-файлах (package-lock.json, yarn.lock, pnpm-lock.yaml) и, в случае обнаружения, перейти на последнюю чистую версию, опубликованную до атаки (с более низким номером патча). Важно также удалить остаточные файлы закрепления в соответствии с операционной системой, ротировать все токены, которые могли оказаться в окружении установки (npm-токены, ключи облачных провайдеров, SSH-ключи), и, если на машине использовались расширения криптовалютных кошельков, рассмотреть миграцию средств на новые кошельки, созданные на чистом устройстве.

Усиление контроля за жизненным циклом зависимостей - установка с отключёнными сценариями (npm install --ignore-scripts), использование белых списков пакетов и задержка принятия свежеопубликованных версий - позволит снизить риск повторения подобных атак. Данный инцидент показал, что даже проверенные пространства имён могут быть скомпрометированы через учётные записи с легитимными правами публикации.

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

Network Indicators

  • 23.254.164.92
  • https://23.254.164.92:8000/update/49890878
  • 23.254.164.123
  • https://23.254.164.123:443/49890878
  • AS54290 (Hostwinds LLC)
  • hwsrv-1327786.hostwindsdns.com
  • hwsrv-1327785.hostwindsdns.com

Code and String Indicators

  • NvmProtocal (Windows Run-key value name)
  • com.nvm.protocal (macOS LaunchAgent label)
  • nvmconf.service (Linux systemd unit name)
  • protocal.cjs (dropped stage-2 filename)
  • NodePackages (drop directory name (Win/mac/Linux variants))
  • .pkg_history / .pkg_logs (loader beacon/marker files)
  • /update/49890878 (stage-2 download path / bot id)

SHA-256 Hashes

  • b122a9873bedf145ae2a7fd024b5f309007dbb025149f4dc4ac3f7e4f32a36a4 - easy-day-js setup.cjs (stage-1 loader)
  • c38954e85bf5433e61e7c8f4230336695624ae88b6953afabf7bf817aa91b638 - easy-day-js@1.11.22 package.json
  • cdec8b20338beb708b5be8d3d7a3041a35a8b0fb92f9186262f312d55ff82066 - loader variant
  • 9570f77a5e1511869f4e554e7166df9fde081f2583e293c2569621792ed7d9c9 - loader variant
  • 221c45a790dec2a296af57969e1165a16f8f49733aeab64c0bbd768d9943badf - stage-2 stealer

npm Packages

  • @mastra/acp 0.2.2
  • @mastra/agent-browser 0.3.2
  • @mastra/agent-builder 1.0.42
  • @mastra/agentcore 0.2.2
  • @mastra/agentfs 0.1.1
  • @mastra/ai-sdk 1.4.6
  • @mastra/arize 1.2.3
  • @mastra/arthur 0.3.3
  • @mastra/astra 1.0.2
  • @mastra/auth 1.0.3
  • @mastra/auth-auth0 1.0.2
  • @mastra/auth-better-auth 1.0.4
  • @mastra/auth-clerk 1.0.3
  • @mastra/auth-cloud 1.1.4
  • @mastra/auth-firebase 1.0.1
  • @mastra/auth-okta 0.0.5
  • @mastra/auth-studio 1.2.4
  • @mastra/auth-supabase 1.0.2
  • @mastra/auth-workos 1.5.3
  • @mastra/azure 0.2.3
  • @mastra/blaxel 0.4.2
  • @mastra/braintrust 1.1.4
  • @mastra/brightdata 0.2.2
  • @mastra/browser-firecrawl 0.1.1
  • @mastra/browser-viewer 0.1.3
  • @mastra/chroma 1.0.2
  • @mastra/claude 1.0.3
  • @mastra/clickhouse 1.10.1
  • @mastra/client-js 1.24.1
  • @mastra/cloud 0.1.24
  • @mastra/cloudflare 1.4.2
  • @mastra/cloudflare-d1 1.0.7
  • @mastra/codemod 1.0.4
  • @mastra/convex 1.2.2
  • @mastra/core 1.42.1
  • @mastra/couchbase 1.0.4
  • @mastra/cursor 0.2.1
  • @mastra/dane 1.0.2
  • @mastra/datadog 1.2.5
  • @mastra/daytona 0.4.2
  • @mastra/deployer 1.42.1
  • @mastra/deployer-cloud 1.42.1
  • @mastra/deployer-cloudflare 1.1.44
  • @mastra/deployer-netlify 1.1.20
  • @mastra/deployer-vercel 1.1.38
  • @mastra/docker 0.3.1
  • @mastra/dsql 1.0.3
  • @mastra/duckdb 1.4.3
  • @mastra/dynamodb 1.0.9
  • @mastra/e2b 0.3.4
  • @mastra/editor 0.11.3
  • @mastra/elasticsearch 1.2.1
  • @mastra/engine 0.1.1
  • @mastra/evals 1.3.1
  • @mastra/express 1.3.31
  • @mastra/fastembed 1.1.3
  • @mastra/fastify 1.3.31
  • @mastra/files-sdk 0.2.1
  • @mastra/gcs 0.2.3
  • @mastra/github-signals 0.1.2
  • @mastra/google-cloud-pubsub 1.0.6
  • @mastra/google-drive 0.1.1
  • @mastra/hono 1.4.26
  • @mastra/inngest 1.5.2
  • @mastra/koa 1.5.14
  • @mastra/laminar 1.2.3
  • @mastra/lance 1.0.7
  • @mastra/langfuse 1.3.6
  • @mastra/langsmith 1.2.4
  • @mastra/libsql 1.13.1
  • @mastra/loggers 1.1.3
  • @mastra/longmemeval 1.0.50
  • @mastra/mcp 1.10.1
  • @mastra/mcp-docs-server 1.1.47
  • @mastra/mcp-registry-registry 1.0.2
  • @mastra/mem0 0.1.14
  • @mastra/memory 1.20.4
  • @mastra/modal 0.2.2
  • @mastra/mongodb 1.9.3
  • @mastra/mssql 1.3.2
  • @mastra/mysql 0.1.1
  • @mastra/nestjs 0.1.15
  • @mastra/node-audio 0.1.8
  • @mastra/node-speaker 0.1.1
  • @mastra/observability 1.14.2
  • @mastra/openai 1.0.2
  • @mastra/opencode 0.0.47
  • @mastra/opensearch 1.0.3
  • @mastra/otel-bridge 1.2.3
  • @mastra/otel-exporter 1.2.3
  • @mastra/perplexity 0.1.1
  • @mastra/pg 1.13.1
  • @mastra/pinecone 1.0.2
  • @mastra/playground-ui 33.0.1
  • @mastra/posthog 1.0.29
  • @mastra/qdrant 1.0.3
  • @mastra/rag 2.2.2
  • @mastra/railway 0.1.1
  • @mastra/react 1.0.1
  • @mastra/redis 1.1.3
  • @mastra/redis-streams 0.0.4
  • @mastra/s3 0.5.3
  • @mastra/s3vectors 1.0.7
  • @mastra/schema-compat 1.2.12
  • @mastra/sentry 1.1.4
  • @mastra/server 2.1.1
  • @mastra/slack 1.3.1
  • @mastra/spanner 1.1.2
  • @mastra/speech-azure 0.2.1
  • @mastra/speech-elevenlabs 0.2.1
  • @mastra/speech-google 0.2.1
  • @mastra/speech-ibm 0.2.1
  • @mastra/speech-murf 0.2.1
  • @mastra/speech-openai 0.2.1
  • @mastra/speech-replicate 0.2.1
  • @mastra/speech-speechify 0.2.1
  • @mastra/stagehand 0.2.5
  • @mastra/tavily 1.0.3
  • @mastra/temporal 0.1.14
  • @mastra/turbopuffer 1.0.3
  • @mastra/twilio 1.0.2
  • @mastra/upstash 1.1.3
  • @mastra/vectorize 1.0.3
  • @mastra/vercel 1.0.1
  • @mastra/voice-aws-nova-sonic 0.1.4
  • @mastra/voice-azure 0.11.2
  • @mastra/voice-cloudflare 0.12.3
  • @mastra/voice-deepgram 0.12.2
  • @mastra/voice-elevenlabs 0.12.2
  • @mastra/voice-gladia 0.12.2
  • @mastra/voice-google 0.12.3
  • @mastra/voice-google-gemini-live 0.12.2
  • @mastra/voice-inworld 0.3.1
  • @mastra/voice-modelslab 0.1.2
  • @mastra/voice-murf 0.12.3
  • @mastra/voice-openai 0.12.3
  • @mastra/voice-openai-realtime 0.12.6
  • @mastra/voice-playai 0.12.2
  • @mastra/voice-sarvam 1.0.2
  • @mastra/voice-speechify 0.12.2
  • @mastra/voice-xai-realtime 0.1.2
  • create-mastra 1.13.1
  • easy-day-js 1.11.22
  • mastra 1.13.1
  • mastraqqq 1.13.1

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