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