Feed
CriticalPublished 8 Jul 2026Updated 11 Jul 202617 packages · 17 versions

@injectivelabs/sdk-ts + 16 sibling packages compromised — wallet-key stealer shipped via GitHub maintainer takeover

Summary

On 2026-07-08 20:59 UTC an attacker with a compromised maintainer GitHub account published @injectivelabs/sdk-ts@1.20.21 and pinned the same 1.20.21 version across 16 sibling @injectivelabs/* wallet + core packages. The malicious release hooked fromMnemonic and fromHex with a trackKeyDerivation telemetry stub that base64-encoded stolen mnemonics/private keys and POSTed them to testnet.archival.chain.grpc-web.injective.network. Injective Labs replaced with 1.20.23 about 49 minutes later; 310 downloads shipped in the window.

crypto-wallet-drainmaintainer-takeoveraccount-takeovercredential-theftobfuscation
Detected by
Socket · Aikido · OX Security
Also known as
Injective sdk-ts 1.20.21 compromise · @injectivelabs 2026-07-08 wallet drain
Ecosystems
npm
Packages tracked
17

What happened

On 2026-07-08 at 20:59:17 UTC an attacker in control of a legitimate maintainer's GitHub account began publishing the malicious @injectivelabs/* 1.20.21 release train. The publish burst spanned 20:59:17 → 21:00:39 UTC — 82 seconds, 17 packages, all shipped as 1.20.21. Injective Labs detected the compromise and shipped the clean 1.20.23 counter-release starting 21:47:52 UTC on the same day, ~49 minutes after the first malicious publish. There is no 1.20.22 — the maintainers versioned straight past the poisoned tag.

Attack chain: maintainer GitHub account, not a credential leak

The malicious code entered the repository through commits authored by a GitHub account that had an established history of legitimate contributions to InjectiveLabs/injective-ts. Socket traced the earliest suspicious activity to 2026-06-08 at 20:06 GMT+2 — a full month before the malicious npm release — with the attacker creating a test branch named test-backdoor-check in the same repository. That branch name reads as reconnaissance (verifying write access without producing visible artifacts on a canonical release branch). One month of dormancy followed before the actual malicious commit was merged and released to npm.

This is a GitHub-side account takeover, not an npm publish-token leak. The distinction matters for detection: the malicious commits pass every content-signal filter (author is an established contributor, branch is a normal feature branch, the diff is a small telemetry-shaped patch) that a passive branch-protection review would rely on. Only behavioral controls — required review by a second maintainer, or 2FA session lifetime limits on the developer account — could have blocked this class of attack.

The payload: trackKeyDerivation

The malicious diff monkey-patches the two BIP-39 / hex key-derivation functions in the SDK:

  • fromMnemonic(mnemonic, options) — the entry point for wallets that derive an Injective account from a BIP-39 seed phrase.
  • fromHex(privateKeyHex) — the entry point for wallets loading a raw private key.

Both are wrapped with a call to trackKeyDerivation, which is presented in the source as a "telemetry stub for anonymized SDK usage metrics." In reality trackKeyDerivation:

  1. Captures the raw mnemonic (marker fm) or private-key hex (marker fh) that just passed through the wrapped function.
  2. Base64-encodes the raw secret and prepends the marker so the operator can reconstruct the wallet on their side without ambiguity between seed and hex material.
  3. Pushes the record onto an in-memory queue with a timestamp.
  4. Schedules a flush that HTTP POSTs the queue to the C2 endpoint under the guise of a normal telemetry call.

C2 endpoint — impersonates Injective testnet infrastructure

The callback host resolves through an obfuscated string in the payload to testnet.archival.chain.grpc-web.injective.network. The domain is deliberately shaped to blend into legitimate Injective testnet gRPC-web infrastructure — a defender doing a spot-check on outbound HTTPS from a dApp backend would see the request go to *.injective.network and plausibly categorize it as normal SDK telemetry.

The full package list — 17 packages pinned to 1.20.21

The published-time ordering (recovered from the public npm registry time map) is a clean 82-second sprint:

| Time (UTC) | Package | Notes | |---|---|---| | 20:59:17 | @injectivelabs/exceptions | Utility package pinned to sdk-ts@1.20.21 | | 20:59:22 | @injectivelabs/networks | Network config | | 20:59:28 | @injectivelabs/sdk-ts | Primary target — the wallet-key-stealer payload | | 20:59:33 | @injectivelabs/ts-types | Type definitions | | 20:59:38 | @injectivelabs/utils | Utilities | | 20:59:43 | @injectivelabs/wallet-base | Wallet abstraction | | 20:59:47 | @injectivelabs/wallet-core | Wallet core | | 20:59:52 | @injectivelabs/wallet-cosmos-strategy | Cosmos wallet strategy | | 20:59:56 | @injectivelabs/wallet-cosmos | Cosmos wallet | | 21:00:06 | @injectivelabs/wallet-evm | EVM wallet | | 21:00:11 | @injectivelabs/wallet-ledger | Ledger HW wallet | | 21:00:15 | @injectivelabs/wallet-magic | Magic auth wallet | | 21:00:20 | @injectivelabs/wallet-private-key | Direct key wallet | | 21:00:24 | @injectivelabs/wallet-strategy | Wallet strategy façade | | 21:00:29 | @injectivelabs/wallet-trezor | Trezor HW wallet | | 21:00:34 | @injectivelabs/wallet-turnkey | Turnkey wallet | | 21:00:39 | @injectivelabs/wallet-wallet-connect | WalletConnect wallet |

Every sibling was pinned to sdk-ts@1.20.21 — so a downstream dApp that never installed @injectivelabs/sdk-ts directly but pulled in any wallet-strategy package would still have resolved to the malicious SDK transitively.

Registry state

All 17 malicious versions are still resolvable on the public npm registry but are marked DEPRECATED with the string SECURITY: version 1.20.21 is compromised. Do not install.. npm deprecation does NOT unpublish tarballs, so a lockfile that pins 1.20.21 will still install malware today. Private registry mirrors (Verdaccio, Artifactory, Nexus) do NOT propagate deprecation warnings — an internal mirror that cached the tarball on 2026-07-08 will keep serving it until manually evicted.

The fixed replacement is 1.20.23 on every package; 1.20.22 does not exist.

Comparison to earlier Injective / crypto ecosystem incidents

This is the second major crypto-wallet-drain npm compromise of 2026 after the Bitwarden CLI TeamPCP incident, and the second known dApp SDK compromise after the dYdX February 2026 incident. Unlike TeamPCP's cross-org bursts, this one stays narrowly inside @injectivelabs — consistent with the "single maintainer GitHub account, no wormable propagation payload" attack shape.

Affected packages (17)

  • npm@injectivelabs/exceptions
    1.20.21
  • npm@injectivelabs/networks
    1.20.21
  • npm@injectivelabs/sdk-ts
    1.20.21
  • npm@injectivelabs/ts-types
    1.20.21
  • npm@injectivelabs/utils
    1.20.21
  • npm@injectivelabs/wallet-base
    1.20.21
  • npm@injectivelabs/wallet-core
    1.20.21
  • npm@injectivelabs/wallet-cosmos
    1.20.21
  • npm@injectivelabs/wallet-cosmos-strategy
    1.20.21
  • npm@injectivelabs/wallet-evm
    1.20.21
  • npm@injectivelabs/wallet-ledger
    1.20.21
  • npm@injectivelabs/wallet-magic
    1.20.21
  • npm@injectivelabs/wallet-private-key
    1.20.21
  • npm@injectivelabs/wallet-strategy
    1.20.21
  • npm@injectivelabs/wallet-trezor
    1.20.21
  • npm@injectivelabs/wallet-turnkey
    1.20.21
  • npm@injectivelabs/wallet-wallet-connect
    1.20.21

Impact

  • Any wallet address whose private key or BIP-39 mnemonic passed through @injectivelabs/sdk-ts@1.20.21 (or one of the 16 sibling @injectivelabs/* packages pinned to 1.20.21) must be considered fully compromised — the fromMnemonic / fromHex key-derivation functions were monkey-patched to base64-encode the raw seed material and POST it to an attacker-controlled endpoint that impersonated legitimate Injective testnet infrastructure
  • Transitive exposure is broad: @injectivelabs/sdk-ts has ~50,000 weekly downloads and ~87 direct dependents on the public npm registry, and the attacker also pinned 1.20.21 on the 16 sibling packages that most Injective dApps consume (wallet strategy packages, wallet-cosmos, wallet-evm, wallet-ledger, wallet-trezor, etc.) — a project that never installed sdk-ts directly could still have resolved the malicious release through a wallet-strategy dependency
  • Exfiltration channel used the domain testnet.archival.chain.grpc-web.injective.network — a subdomain shape designed to look like real Injective testnet gRPC-web infrastructure so casual outbound-traffic review would see the callback as legitimate
  • Root cause was a maintainer GitHub account takeover, not a credential leak of the npm publish tokens. Suspicious commits (branch test-backdoor-check) trace back to 2026-06-08 20:06 CEST — a full month of dormant reconnaissance before the malicious release burst on 2026-07-08. The commits were pushed by a developer account with an established commit history on the repo, so branch-protection review by content would not have flagged the actor
  • Socket recorded 310 downloads of the malicious 1.20.21 before Injective Labs shipped the clean 1.20.23 replacement 49 minutes later — small in absolute terms but large enough to expect at least a handful of impacted wallets given the sensitivity of the affected functions
  • The malicious 1.20.21 versions are deprecated but still resolvable on the npm registry (npm deprecation does not unpublish); npm records SECURITY: version 1.20.21 is compromised. Do not install. in the deprecation field. A CI/CD pipeline that pins ~1.20.21 or ^1.20.0 and does not upgrade past 1.20.23 will still install the malware

What to do

  1. 1Grep every lockfile (package-lock.json, yarn.lock, pnpm-lock.yaml, deno.lock) for 1.20.21 under any @injectivelabs/* scope. Any match is a wallet compromise: any mnemonic, seed phrase, or private key that the affected process handled during the window must be assumed exfiltrated
  2. 2Migrate off 1.20.21 to the fixed @injectivelabs/sdk-ts@1.20.23 (and the matching 1.20.23 on every sibling package). Note: no 1.20.22 exists — the maintainers versioned straight past the malicious release
  3. 3If your build ever installed 1.20.21, treat every wallet key or mnemonic that was in scope of the affected process as compromised: move funds to a fresh wallet with a freshly-derived key that never touched the affected host. Do not simply "rotate" the key on the same host — the whole environment should be treated as suspect
  4. 4Audit outbound network traffic from any build host / dApp backend for connections to testnet.archival.chain.grpc-web.injective.network. This is the known C2 host; any resolution or connection to it during 2026-07-08 20:59 UTC through 2026-07-08 21:48 UTC indicates active exfiltration
  5. 5Register defensive stubs on the public npm registry for any private wallet-adjacent package name your org uses, so future scope-hijack attempts against your Injective / Cosmos SDK integrations cannot resolve. Pin .npmrc scope routing so @injectivelabs/* only resolves through the public registry (not through a proxy that might cache the malicious tarball)
  6. 6On any impacted host, invalidate every credential the process could reach: npm publish tokens, GitHub PATs, cloud SDK credentials, exchange API keys, and any code-signing certificate reachable from the wallet environment. Assume the entire host is compromised and re-image
  7. 7Verify your internal Verdaccio / Artifactory / Nexus mirror has purged the 1.20.21 tarballs — deprecation on the public registry does NOT propagate into private mirrors, which will keep serving the malicious version until you explicitly evict the tarball

References

npm-2026-07-08-injectivelabs-sdk-ts-crypto-wallet-drain