# @injectivelabs/sdk-ts and 16 sibling packages ship a wallet key stealer

> 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.

- Published: 2026-07-08
- Last updated: 2026-07-11
- Severity: critical
- Kind: Compromise - A legitimate, already-used package, maintainer account, CI pipeline, or release tag was hijacked and a malicious version was published under a name people already depend on.
- Ecosystems: npm
- Scope: 17 packages, 17 compromised versions
- Tags: crypto-wallet-drain, maintainer-takeover, account-takeover, credential-theft, obfuscation
- Also known as: Injective sdk-ts 1.20.21 compromise, @injectivelabs 2026-07-08 wallet drain
- Detected by: Socket, Aikido, OX Security
- Incident ID: npm-2026-07-08-injectivelabs-sdk-ts-crypto-wallet-drain

## Affected packages (17)

Only the exact versions listed were named by the source advisories. Other versions are not implicated.

| Package | Ecosystem | Compromised versions |
|---|---|---|
| [@injectivelabs/exceptions](https://dependencywatch.io/package/npm/@injectivelabs/exceptions) | npm | 1.20.21 |
| [@injectivelabs/networks](https://dependencywatch.io/package/npm/@injectivelabs/networks) | npm | 1.20.21 |
| [@injectivelabs/sdk-ts](https://dependencywatch.io/package/npm/@injectivelabs/sdk-ts) | npm | 1.20.21 |
| [@injectivelabs/ts-types](https://dependencywatch.io/package/npm/@injectivelabs/ts-types) | npm | 1.20.21 |
| [@injectivelabs/utils](https://dependencywatch.io/package/npm/@injectivelabs/utils) | npm | 1.20.21 |
| [@injectivelabs/wallet-base](https://dependencywatch.io/package/npm/@injectivelabs/wallet-base) | npm | 1.20.21 |
| [@injectivelabs/wallet-core](https://dependencywatch.io/package/npm/@injectivelabs/wallet-core) | npm | 1.20.21 |
| [@injectivelabs/wallet-cosmos](https://dependencywatch.io/package/npm/@injectivelabs/wallet-cosmos) | npm | 1.20.21 |
| [@injectivelabs/wallet-cosmos-strategy](https://dependencywatch.io/package/npm/@injectivelabs/wallet-cosmos-strategy) | npm | 1.20.21 |
| [@injectivelabs/wallet-evm](https://dependencywatch.io/package/npm/@injectivelabs/wallet-evm) | npm | 1.20.21 |
| [@injectivelabs/wallet-ledger](https://dependencywatch.io/package/npm/@injectivelabs/wallet-ledger) | npm | 1.20.21 |
| [@injectivelabs/wallet-magic](https://dependencywatch.io/package/npm/@injectivelabs/wallet-magic) | npm | 1.20.21 |
| [@injectivelabs/wallet-private-key](https://dependencywatch.io/package/npm/@injectivelabs/wallet-private-key) | npm | 1.20.21 |
| [@injectivelabs/wallet-strategy](https://dependencywatch.io/package/npm/@injectivelabs/wallet-strategy) | npm | 1.20.21 |
| [@injectivelabs/wallet-trezor](https://dependencywatch.io/package/npm/@injectivelabs/wallet-trezor) | npm | 1.20.21 |
| [@injectivelabs/wallet-turnkey](https://dependencywatch.io/package/npm/@injectivelabs/wallet-turnkey) | npm | 1.20.21 |
| [@injectivelabs/wallet-wallet-connect](https://dependencywatch.io/package/npm/@injectivelabs/wallet-wallet-connect) | npm | 1.20.21 |

## 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](https://dependencywatch.io/incident/npm-2026-04-22-bitwarden-cli-teampcp), and the second known dApp SDK compromise after the [dYdX February 2026 incident](https://dependencywatch.io/incident/multi-2026-01-27-dydx-compromise). 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.

## 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. Grep 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. Migrate 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. If 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. Audit 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. Register 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. On 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. Verify 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

## Check your own dependencies

- Check a package-lock.json against this incident: https://dependencywatch.io/check/package-lock-json

The scan runs entirely in the browser; lockfile contents are never uploaded.

## References

- [Compromised Injective SDK npm Package Exfiltrates Wallet Keys Through Fake Telemetry](https://socket.dev/blog/compromised-injective-sdk-npm-package) - Socket
- [Injective SDK on npm infected with cryptocurrency wallet stealer](https://www.bleepingcomputer.com/news/security/injective-sdk-on-npm-infected-with-cryptocurrency-wallet-stealer/) - BleepingComputer
- [Injective Labs GitHub Compromise Pushes Wallet-Key-Stealing npm Packages](https://thehackernews.com/2026/07/injective-labs-github-compromise-pushes.html) - The Hacker News
- [Compromised @injectivelabs/sdk-ts exfiltrates wallet keys through fake telemetry](https://www.aikido.dev/blog/compromised-injectivelabs-exfiltrates-keys) - Aikido
- [Injectivelabs npm Package Hijacked, Impacting 87 Dependent Packages](https://www.ox.security/blog/injectivelabs-npm-package-hijacked-impacting-87-dependent-packages/) - OX Security
- [@injectivelabs/sdk-ts on npm - deprecation notice for 1.20.21](https://www.npmjs.com/package/@injectivelabs/sdk-ts) - npm
- [Compromised Injective SDK sends wallet keys through fake telemetry](https://crypto.news/compromised-injective-sdk-sends-wallet-keys-through-fake-telemetry/) - crypto.news
- [Injective Labs SDK npm package compromised to steal cryptocurrency keys](https://www.scworld.com/brief/injective-labs-sdk-npm-package-compromised-to-steal-cryptocurrency-keys) - SC World

---

Canonical page: https://dependencywatch.io/incident/npm-2026-07-08-injectivelabs-sdk-ts-crypto-wallet-drain
Markdown version: https://dependencywatch.io/incident/npm-2026-07-08-injectivelabs-sdk-ts-crypto-wallet-drain.md
Site index for agents: https://dependencywatch.io/llms.txt
DependencyWatch.io is operated by Precursor Security (https://precursorsecurity.com).
