Инцидент, затронувший экосистему блокчейна Injective, выявил опасный вектор атаки на цепочку поставок программного обеспечения. Специалисты по безопасности из компаний Socket и SlowMist независимо друг от друга обнаружили, что версия 1.20.21 популярного npm-пакета @injectivelabs/sdk-ts содержит вредоносные фрагменты. Этот пакет широко применяется разработчиками для работы с сетью Injective: формирования и подписания транзакций, запросов данных из блокчейна, а также генерации и импорта ключей кошельков. Поскольку код напрямую обрабатывает мнемонические фразы и приватные ключи, любое вмешательство в его работу представляет прямую угрозу для всех пользователей, которые доверили ему свои криптоактивы.
Описание
Исследование началось с анализа платформой Socket аномального сетевого поведения в среде выполнения Node.js. Одновременно система мониторинга SlowMist MistEye, специализирующаяся на угрозах в Web3, зафиксировала подозрительную активность и выдала предупреждение. Важно подчеркнуть, что обнаруженный образец не был подделкой или клоном. Пакет являлся официальной сборкой, скомпрометированной на этапе разработки или публикации. Вредоносный код не активировался при установке - он встраивался в путь вывода ключей и срабатывал только при вызове определённых функций.
Поведение злонамеренной вставки детально описано в предоставленном анализе SlowMist. В скомпилированном модуле accounts были найдены вызовы функции trackKeyDerivation, которая принимала аргументы из методов generate(), fromMnemonic() и fromHex() при передаче строкового приватного ключа. Комментарии в коде маскировали эту активность под сбор телеметрии для оптимизации SDK. Однако телеметрия не должна обрабатывать незашифрованные корневые секреты. В данном случае функция получала полную мнемоническую фразу или приватный ключ без какой-либо анонимизации. Если в метод fromHex передавался массив байтов, то записывалась только метка "bytes" без самих данных.
Процесс эксфильтрации был спроектирован так, чтобы снизить заметность. Каждая запись форматировалась как "метод:содержимое:временная метка" (fm для мнемоники, fh для ключа). Записи помещались в глобальную очередь и накапливались около двух секунд. Затем они объединялись через символ |, кодировались в Base64 (схема кодирования двоичных данных в текстовый формат, не являющаяся шифрованием) и помещались в HTTP-заголовок X-Request-Id POST-запроса. Тело запроса оставалось пустым. Для передачи использовался API fetch, а в случае его отсутствия - модуль Node.js https.request. Ошибки соединения игнорировались, чтобы не нарушать работу легитимных функций кошелька.
Ключевым элементом маскировки стало использование официального поддомена injective.network - testnet.archival.chain.grpc-web.injective.network. Адрес не был записан в коде открытым текстом, а собирался из числовых кодов символов. Прямой HTTP GET-запрос к этому узлу возвращал ответ 501 Not Implemented. POST-запрос с пустым телом и gRPC-Web заголовками давал ответ grpc-status: 12, что соответствует стандартному поведению тестового gRPC-Web шлюза. Это означает, что сервер принимает запросы, но не подтверждает, что заголовки с данными записываются, обрабатываются или передаются злоумышленнику. DNS-резолвинг на момент проверки указывал на IP-адрес 15.235.87.88, но этот результат может меняться.
Хотя код однозначно подтверждает намерение отправить приватные ключи, для их фактической кражи должны одновременно выполняться два условия: шлюз или система логирования должны фиксировать заголовок X-Request-Id, и злоумышленник должен иметь доступ к этим журналам. На данный момент нет доказательств взлома официальной инфраструктуры Injective. Тем не менее, сам факт наличия такого механизма в сертифицированном пакете ставит под угрозу все ключи, которые когда-либо были сгенерированы или импортированы через версию 1.20.21.
Пользователям, использующим этот компонент, следует в первую очередь проверить свои файлы package-lock.json, yarn.lock, директории node_modules, образы контейнеров и сборочные артефакты на наличие версии 1.20.21. Если она обнаружена, необходимо срочно обновить пакет до безопасной версии, подтверждённой мейнтейнерами. Ни в коем случае нельзя полагаться лишь на очистку кэша и продолжать использовать те же мнемонические фразы или ключи. Все мнемоники, приватные ключи и тестовые ключи, полученные через скомпрометированную версию, следует считать потенциально раскрытыми. Для кошельков с высокой стоимостью активов необходимо сгенерировать новые ключи, перевести средства и отозвать все разрешения, роли контрактов и привилегии автоматической подписи, связанные со старыми адресами.
Администраторам систем рекомендуется проверить журналы DNS, прокси-серверов и исходящего трафика на предмет обращений к testnet.archival.chain.grpc-web.injective.network. При обнаружении таких запросов нужно сохранить логи и ограничить доступ к ним, чтобы данные из заголовка X-Request-Id не попали в обычные заявки и чаты. Также следует проанализировать журналы браузеров, Node.js, CI/CD систем и файрволов на наличие POST-запросов с пустым телом, заголовком X-Request-Id и Content-Type: application/grpc-web+proto. Для долгосрочного контроля зависимости рекомендуется использовать Software Bill of Materials (SBOM) и автоматическое сканирование образов. Мейнтейнеры пакета должны провести аудит учётных записей npm, GitHub Actions, механизмов trusted publishing, сборочных машин и процессов релизов, чтобы исключить повторное внедрение вредоносного кода.
Индикаторы компрометации
MD5
- 06c9394afab853bcbca15f354ef0d72a
- 9b37a86aad8a5e191c1b8c3397848503
- d72bdb86962a4bb673619945175f6378
SHA1
- 4bfbe6c80d0fb9983c21288fdfaa23c1cc8744e4
- 9233c753a5a4b0f89d1ae0f4ecf6a74fd8d9eff1
- e9bf2a19038b34e9cc6239a4849b3d5a9bd98aef
SHA256
- 103c4e6181151c1bcfedc41506cd1815458c38375d08a8fcd9981dbe0b965ce0
- 624ac118eb5e66d6d313424d375021298bf8a809925a7c642300a41fd672a05d
- 9a59eb454f3ca3fe91214136ee5edd417cc47a80e6f169b52099d6561944baf9
Malicious Dependency
- @injectivelabs/sdk-ts@1.20.21
Affected Dependencies
- @injectivelabs/utils@1.20.21
- @injectivelabs/networks@1.20.21
- @injectivelabs/ts-types@1.20.21
- @injectivelabs/exceptions@1.20.21
- @injectivelabs/wallet-base@1.20.21
- @injectivelabs/wallet-core@1.20.21
- @injectivelabs/wallet-cosmos@1.20.21
- @injectivelabs/wallet-private-key@1.20.21
- @injectivelabs/wallet-evm@1.20.21
- @injectivelabs/wallet-trezor@1.20.21
- @injectivelabs/wallet-cosmostation@1.20.21
- @injectivelabs/wallet-ledger@1.20.21
- @injectivelabs/wallet-wallet-connect@1.20.21
- @injectivelabs/wallet-magic@1.20.21
- @injectivelabs/wallet-strategy@1.20.21
- @injectivelabs/wallet-turnkey@1.20.21
- @injectivelabs/wallet-cosmos-strategy@1.20.21