Hintergrund
Der Ausgangspunkt dieser Untersuchung war ein scheinbar normaler Entwicklungsablauf: Entwickler installieren das offizielle Injective SDK, erzeugen Wallets, importieren Seed Phrases oder übergeben vorhandene private Schlüssel an die SDK-Schnittstelle. In der Installationsphase läuft alles wie erwartet, und Wallet-Operationen können möglicherweise auch korrekt Ergebnisse liefern. Gleichzeitig taucht jedoch im Hintergrund des Programms eine zusätzliche Netzwerkanforderung auf, die nicht Teil der normalen Geschäftslogik ist.
In letzter Zeit entdeckte das Sicherheitsforschungsunternehmen Socket im Rahmen von Threat Hunting in dem npm-Ökosystem ein abnormales Verhalten in der Version 1.20.21 von @injectivelabs/sdk-ts. Das Sicherheitsüberwachungssystem SlowMist MistEye erfasste ebenfalls diesen bösartigen Supply-Chain-Angriffsfall. Nach der Analyse wurde bestätigt, dass es sich bei dem betreffenden Artefakt nicht um eine nachgebaute Imitation des Angreifers handelt, sondern um ein offizielles SDK-Build-Produkt, das bösartigen Code enthält. Weitere öffentlich verfügbare Hintergründe finden Sie unter (Compromised Injective SDK npm Package).
@injectivelabs/sdk-ts wird normalerweise für das Abfragen von On-Chain-Daten, das Erstellen von Transaktionen, das Signieren sowie das Importieren oder Generieren von Wallet-Keys verwendet. Sein Code greift direkt auf Mnemonics und Private Keys zu und ist daher eine Komponente, der man sehr stark vertrauen können muss. Die lokale statische Analyse bestätigt: Der bösartige Code schiebt nach dem Aufruf bestimmter Private-Key-Ableitungs-Interfaces das Mnemonic oder den Private Key im String-Format in eine Warteschlange, kodiert es anschließend mit Base64 und legt es in den X-Request-Id-Request-Header. Danach sendet er es per HTTP POST.
MistEye-Antwort
MistEye ist ein von SlowMist eigenständig entwickeltes Web3-Threat-Intelligence- und dynamisches Security-Monitoring-System. Es integriert Security-Monitoring- und Intelligence-Aggregationsfähigkeiten und bietet Nutzern Echtzeit-Risiko-Warnungen sowie Asset-Schutz.
Nachdem das MistEye-System den Vorfall einer Supply-Chain-Invasion in dem Injective offiziellen SDK abgefangen hatte, hat das System eine Alarmierung ausgelöst und die Angriffskette vollständig analysiert. Der Bericht deckt die Eintragsstellen des bösartigen Codes, die Datenkodierung und Exfiltrationskanäle, die Zieladresse, Versionsunterschiede sowie die extrahierbaren IOCs ab. Die entsprechenden Threat-Intelligence-Daten können über die MistEye-API und Abhängigkeits-Scanning-Tools weiter untersucht werden.

Im Folgenden wird die Untersuchung anhand der Hinweisspuren ausgeführt.
Technische Analyse
Hinweis eins: In der Installationsphase wurden keine eindeutigen Spuren hinterlassen.
Die Untersuchung startete bei package.json. In etwa Zeile 485–500 wurden keine Installations-Lifecycle-Skripte wie postinstall oder preinstall gefunden. Ein simples Installieren dieser Version löst keine Exfiltration automatisch aus; daher lässt sich anhand nur der Installationslogs vermutlich nichts Auffälliges erkennen.
Doch das bedeutet nicht, dass das Paket sicher ist. Der bösartige Code wurde in den Schlüssel-Ableitungs-Pfad des SDK eingebettet; der Trigger ist nicht die Installation, sondern die tatsächliche Anwendung der Wallet-API durch die App.
Hinweis zwei: Das normale SDK-Äußere verschleiert die ungewöhnlichen Parameter.
Der Paketname des Samples, die README und die meisten Build-Codes behalten ein normales Aussehen. Der bösartige Block befindet sich in der accounts-Build-Datei; in Kommentaren werden Formulierungen wie key-derivation-telemetry, anonymized usage metrics und SDK optimization verwendet. Optisch wirkt es wie ein Datenstatistik-Modul innerhalb des SDK selbst.
Normales Telemetrie-Logging erfasst normalerweise nur Methodennamen oder die Aufbaudauer. Hier empfängt der Code jedoch direkt vollständige Mnemonics oder stringförmige Private Keys und führt keinerlei Anonymisierung, Hashing oder Maskierung durch. Das ist der erste entscheidende Widerspruch: Die Kommentare behaupten, Statistik zu machen, doch die Parameter tragen tatsächlich die Wallet-Wurzel-Schlüssel.
Hinweis drei: Welche Aufrufe das Aufzeichnen des Schlüssels auslösen.
Man kann die Triggerpfade in drei Fälle einteilen:
PrivateKey.generate() erzeugt zuerst das Mnemonic und ruft anschließend weiter fromMnemonic() auf.
PrivateKey.fromMnemonic(words) übergibt das vollständige Mnemonic an trackKeyDerivation().
Die String-Variante PrivateKey.fromHex(privateKey) übergibt den vollständigen Private Key an dieselbe Logging-Funktion.
fromPrivateKey() selbst ruft trackKeyDerivation() nicht auf, daher lässt sich nicht pauschal sagen, dass alle Private-Key-Schnittstellen eine Exfiltration auslösen.
Der Schlüsselcode befindet sich in dist/esm/accounts-jQ1GSgaW.js in den Zeilen 989–1006 und 1024–1028:

String-Eingaben werden unverändert in die Warteschlange gelegt; Byte-Array-Eingaben werden nur als festes Wort „bytes“ protokolliert und enthalten nicht die konkreten Byte-Werte.
Beweisbewertung: Der Quellcode kann bestätigen, dass das Schlüsselmaterial in eine zusätzliche Logging-Funktion gelangt, aber er kann nicht bestätigen, ob die Anfrage tatsächlich das Ziel erreicht hat, und auch nicht, ob die Daten bereits ausgelesen wurden.
Hinweis vier: Die Daten werden nicht sofort exfiltriert.
Die Logging-Funktion schreibt jede Dateneinheit als „Methode: Inhalt: Zeitstempel“. fm steht für Mnemonic, fh für hexadezimale Private Keys. Das Programm legt die Aufzeichnungen zuerst in eine globale Warteschlange, wartet dann ca. 2 Sekunden; falls währenddessen mehrfach Schlüsselableitungen stattfinden, werden die Einträge mit | zu einer Batch zusammengefasst.

Datei: dist/esm/accounts-jQ1GSgaW.js, Zeilen 950–971.
Anschließend verwendet das Programm Base64-Kodierung. Base64 ist nur eine andere Darstellung von Zeichen, keine Verschlüsselung; der Empfänger kann es direkt zurückkonvertieren. Warten und Batch-Senden reduzieren zwar die Anzahl der Requests und verändern die Form einzelner Einträge im Netzwerk, aber sie ändern nicht die Sensitivität der Daten.

Hinweis fünf: Die Exfiltrationsanfrage wird als normaler Aufruf getarnt, aber es gibt klare Bruchstellen.
Die Sendefunktion nutzt vorrangig fetch: Sie setzt die Daten in den X-Request-Id-Request-Header und der Body ist leer. Wenn fetch nicht verfügbar ist und __require verfügbar ist, wird als Rückfall auf Node.js https.request umgeschaltet.

Der Request verwendet einen Content-Type im gRPC-Web-Stil, aber im Quellcode sind keine Vertragsadresse, kein Methodenname, kein Protobuf-Transaktionskörper, keine Signaturdaten oder eine Broadcast-Schnittstelle auffindbar. Er fordert den Pfad „/“ an, der Body ist leer, und die Schlüssel-Daten erscheinen nur im Request-Header. Mit anderen Worten: Das ist kein normaler Contract-Call, sondern ein Daten-Exfiltrationsversuch über HTTP.
Der Browser-Zweig keepalive versucht nur, die Anfrage beim Schließen der Seite am Leben zu halten; es kann den Abschluss nicht garantieren. Wenn die Anfrage fehlschlägt, werden Ausnahmen und asynchrone Fehler stillschweigend ignoriert, und normale Wallet-Operationen laufen dennoch weiter; zudem wird der Antwortinhalt des Servers nicht geparst und ausgeführt.

Zu beachten ist: Wenn ein Proxy, eine Firewall, eine App-Überwachung oder Debug-Logs die X-Request-Id aufzeichnen, kann dort das Base64-kodierte Mnemonic oder der Private Key gespeichert sein. Für die weitere Untersuchung muss man klären, ob und welche Zugriffsrechte für Log-Plattformen, Backend-Speicher und Service-Accounts vorhanden sind. Der Code selbst bietet jedoch keinerlei Fähigkeiten für den Serverzugriff oder das Lesen von Logs.
Hinweis sechs: Die Zieladresse liegt unter der offiziellen Domain, aber es lässt sich nicht bestätigen, wer die Datenempfänger sind.
Der Hostname wird nicht als Klartext im Code gespeichert, sondern in ein Zahlenarray zerlegt und dann über String.fromCharCode wiederhergestellt:

Statische Dekodierung ergibt: testnet[.]archival[.]chain[.]grpc-web[.]injective[.]network.
Weitere Prüfungen zeigten, dass diese Adresse zum offiziellen Domain- und Infrastruktur-Ökosystem von Injective gehört. In dem aktuellen Bericht wurde vermerkt, dass sie 15[.]235[.]87[.]88 aufgelöst hat; die DNS-Ergebnisse ändern sich je nach Zeitpunkt und Abfrageposition, daher kann man allein damit keine Kontrolle durch einen Dienst ableiten. Die Dokumentation der öffentlichen Endpunkte von Injective führt testnet[.]sentry[.]chain[.]grpc-web[.]injective[.]network auf; die archivierte Knoten-Dokumentation erläutert, dass es ein offizielles Archiv-Gateway-Konzept gibt, aber in der öffentlich verfügbaren Liste wird kein eigener archival-Host separat aufgeführt.
Bei Sondierungen ohne tatsächliche Daten liefert der Zugriff auf dieses Ziel mit einem normalen GET-Request 501 Not Implemented. Mit einer leeren gRPC-Web-Stil POST-Anfrage (Body leer) erhält man grpc-status: 12 und malformed method name: „/“. Das entspricht der Standardantwort des offiziellen Testnet gRPC-Web-Endpunkts. Das zeigt, dass das Ziel aktuell einen Gateway-ähnlichen Dienst ausführt, aber es bedeutet nicht, dass der Schlüssel vom Server gespeichert wurde.
Damit die Daten tatsächlich erlangt werden, müssen zwei Bedingungen gleichzeitig erfüllt sein: Das Gateway oder das Log-System zeichnet den Request-Header auf, und der Angreifer hat Zugriff auf diese Logs oder die Leseberechtigung für das Backend-Storage. Aktuell gibt es keine Hinweise darauf, dass offizielle Server oder Log-Systeme vom Angreifer kontrolliert wurden.

Zusammenfassung
Diese Untersuchungskette beantwortet am Ende vier Fragen:
Wann es ausgelöst wird: beim Aufruf von generate(), fromMnemonic() oder der String-Variante von fromHex().
Was gesendet wird: das vollständige Mnemonic oder ein privaten Schlüssel im String-Format; Byte-Arrays werden nur als bytes aufgezeichnet.
Wie gesendet wird: etwa 2 Sekunden warten, dann Base64-kodieren und in den X-Request-Id-Request-Header eines leeren POST-Requests einfügen.
Wie weit bestätigt werden kann: Der Quellcode bestätigt die Konstruktionslogik der Exfiltrationsanfrage und das offizielle Ziel, kann jedoch nicht bestätigen, ob der Schlüssel vom Serverseite gespeichert, protokolliert, weitergeleitet oder auf die Kette übermittelt wurde.
Für Nutzer ist das dringendste Problem nicht zu bestätigen, wer den Server kontrolliert, sondern ob der Schlüssel über die betroffenen Schnittstellen verarbeitet wurde. Falls in dieser Version abgeleitet oder importiert wurde, sollten Maßnahmen ergriffen werden, da der Schlüssel möglicherweise geleakt wurde.
Empfehlung:
Prüfen Sie den Abhängigkeitsbaum, Dependency-Lock-Dateien, Caches, Container-Images und die vorgebauten Frontend-Assets und stellen Sie sicher, dass @injectivelabs/sdk-ts@1.20.21 nicht weiter in die Build-Umgebung gelangt.
Auf die sichere Version upgraden, die vom Maintainer bestätigt und von der Organisation selbst verifiziert wurde; löschen Sie nicht nur den Cache und verwenden Sie dann weiterhin die ursprünglichen Wallet-Schlüssel.
Erfassen Sie alle Mnemonics, Private Keys und Testschlüssel, die über dieses SDK abgeleitet oder importiert wurden. Generieren Sie neue Schlüssel für wertvolle Wallets und übertragen Sie Assets. Widerrufen Sie zudem die Autorisierung, Contract-Rollen und automatischen Signaturrechte der alten Adressen.
Suchen Sie in DNS-, Proxy- und Exit-Logs nach testnet[.]archival[.]chain[.]grpc-web[.]injective[.]network, bewahren Sie die relevanten Logs zuerst auf und überwachen Sie sie; nachdem Sie ungewöhnliche Anfragen festgestellt haben, beschränken Sie die ungewöhnliche Datenlast gemäß den Richtlinien der Organisation.
Überprüfen Sie die Logs von Browser, Node.js, Continuous Integration und Continuous Delivery (CI/CD), sowie von Proxys und Firewalls. Achten Sie besonders auf POST-Requests mit X-Request-Id, application/grpc-web+proto und leerem Body. Logs mit solchen Headern sollten eingeschränkt werden, um eine Weitergabe an normale Tickets oder Chat-Verläufe zu vermeiden.
Nutzen Sie Software-Inventory (SBOM), lockfile, node_modules, Artifact-Repositorys und Image-Scanning, um direkte und transitive Abhängigkeiten zu scannen und sicherzustellen, dass 1.20.21 nicht weiter in die Build-Umgebung gelangt.
Maintainer sollten die npm-Publikationskonten, GitHub Actions, vertrauenswürdige npm-Publikations- und Identity-Token-Konfigurationen, Build-Hosts und den Veröffentlichungsprozess auditieren. Wenn Sie bestätigen müssen, ob ein GitHub-Account kompromittiert wurde, wann die Veröffentlichung erfolgte, wie viele Downloads es gab oder wie sich Abhängigkeiten verbreitet haben, sollten Sie die Veröffentlichungsplattform-Datensätze und die Audit-Logs der Organisation unabhängig verifizieren.
IOC
Bösartige Abhängigkeit
@injectivelabs/sdk-ts@1.20.21
Betroffene Abhängigkeitspakete (alle indirekten Abhängigkeiten von @injectivelabs/sdk-ts@1.20.21)
@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
Bösartige Datei
filename: injectivelabs__sdk-ts-1.20.21-socket-raw-reconstructed.tar.gz
MD5: d72bdb86962a4bb673619945175f6378
SHA1: 9233c753a5a4b0f89d1ae0f4ecf6a74fd8d9eff1
SHA256: 624ac118eb5e66d6d313424d375021298bf8a809925a7c642300a41fd672a05d
filename: dist/cjs/accounts-Cy0p4lLW.cjs
MD5: 9b37a86aad8a5e191c1b8c3397848503
SHA1: 4bfbe6c80d0fb9983c21288fdfaa23c1cc8744e4
SHA256: 103c4e6181151c1bcfedc41506cd1815458c38375d08a8fcd9981dbe0b965ce0
filename: dist/esm/accounts-jQ1GSgaW.js
MD5: 06c9394afab853bcbca15f354ef0d72a
SHA1: e9bf2a19038b34e9cc6239a4849b3d5a9bd98aef
SHA256: 9a59eb454f3ca3fe91214136ee5edd417cc47a80e6f169b52099d6561944baf9
Über MistEye
MistEye ist eine von SlowMist eigenständig entwickelte Web3-Threat-Intelligence- und dynamische Security-Monitoring-Plattform. Sie bietet über APIs Fähigkeiten zur Erkennung bösartiger Aktivitäten sowie zur Warnung vor Supply-Chain-Risiken im Ökosystem quelloffener Pakete.
Alle bösartigen Pakete und IOCs, die an dieser Aktion beteiligt sind, wurden in die MistEye-Threat-Detection-Engine integriert. Entwickler können über die API automatisiert die Projektabhängigkeiten prüfen, schnell feststellen, ob bekannte bösartige Pakete betroffen sind, und Hinweise zur Eindämmung erhalten.
📖 API-Dokumentation: https://app.misteye.io/api-docs
🛠️ MistEye-DepScan: https://github.com/slowmist/MistEye-DepScan – leichtgewichtiges CLI-Tool, das mit einem einzigen Befehl die Projektabhängigkeiten sowie bekannte bösartige Pakete in global installierten Paketen scannt; unterstützt npm / PyPI / Cargo / Go / RubyGems-Ökosysteme
🛠️ MistEye-Skills: https://github.com/slowmist/misteye-skills – AI-Coding-Assistent-Security-Skills-Paket; löst vor der Abhängigkeitsinstallation und dem URL-Zugriff automatisch die MistEye-Sicherheitsprüfung aus
Dieser Artikel wurde vom SlowMist Threat-Intelligence-Team in Kombination mit dem MistEye Threat-Intelligence-System sowie dem SlowMist Agent AI-gesteuerten Analyseprozess verfasst. Bei Fragen wenden Sie sich bitte gerne an uns oder geben Sie Feedback.

