Injective Labs npm Supply-Chain Compromise

A trusted maintainer's identity was used to publish a backdoored @injectivelabs/sdk-ts@1.20.21 (plus 17 scoped packages) that steals crypto wallet mnemonics and private keys — a ~49-minute window on 2026-07-08.
Threat
Injective SDK npm backdoor
Severity
ACTIVE SUPPLY-CHAIN
Type
Package supply-chain · wallet stealer
Access
OIDC trusted-publisher abuse
Version
v0.2 · 2026-07-11
Author
HuntPack
Confidence
High (multi-vendor)
01

Executive Summary

On 2026-07-08, a threat actor published a backdoored release of @injectivelabs/sdk-ts — a TypeScript SDK with roughly 175k monthly downloads used to build crypto wallets, trading bots, DEX front-ends, and DeFi tooling. The malicious commits were authored and pushed under the identity of an existing trusted maintainer and shipped through the project's own GitHub OIDC trusted-publisher (provenance) pipeline, so the poisoned 1.20.21 release carried an air of legitimacy.

The backdoor hooks two key-derivation functions — PrivateKey.fromMnemonic() and PrivateKey.fromHex() — via a trackKeyDerivation() routine. Every time a downstream app derives a key, the BIP-39 mnemonic or raw private key is captured, base64-encoded, and smuggled inside the X-Request-Id HTTP header of a request to testnet.archival.chain.grpc-web.injective[.]network. The actor also pinned 1.20.21 across 17 additional @injectivelabs-scoped packages, exposing transitive dependents who never installed the SDK directly. The malicious version was live for about 49 minutes (downloaded ~310 times) before maintainers reverted and published clean 1.20.23; the deprecated version and GitHub release artifacts may still be reachable.

Defender priority: Treat any crypto wallet key or mnemonic handled on a host that resolved 1.20.21 as compromised — rotate immediately. The single highest-fidelity endpoint catch is DNS/beacon to the exfil host testnet.archival.chain.grpc-web.injective.network (Q1); the authoritative catch is an SCA/lockfile sweep for the poisoned version and its 17 sibling packages (Section 7).

02

Source Review & Web Hunter Notes

TierSourceKey FindingCarry Fwd
1 — Vendor primarySocket Threat Research (2026-07-09)Full package list (sdk-ts + 17 scoped), exfil endpoint, trackKeyDerivation() / fromMnemonic() / fromHex() hooks, sample SHA-256s.yes
1 — Vendor primaryDatadog Security Labs (2026-07-09)Independent teardown: base64 secrets smuggled in the X-Request-Id header; 49-minute window (20:59→21:48 UTC 2026-07-08); versions 1.20.21 → 1.20.23.yes
2 — Reputable pressBleepingComputer (2026-07-09)~175k weekly downloads; GitHub repo compromise; deprecated-not-removed status.yes
2 — Reputable pressThe Hacker News (2026-07-09)OIDC trusted-publisher abuse under maintainer identity; 310 downloads; 17 transitive packages.yes

Two independent vendor teardowns (Socket + Datadog) agree on the exfil host and the hooked functions; this is high-confidence intel. The exfil hostname is a lookalike of legitimate Injective infrastructure — scope carefully before global blocking (see Q1 tuning).

03

Hunt Brief & Attack Chain

Hunt hypotheses (fidelity-ordered)

  1. H1 (high): A developer/build/wallet host resolved or beaconed to testnet.archival.chain.grpc-web.injective.network. → Q1
  2. H2 (high, native): A repo lockfile or node_modules pins any @injectivelabs package at 1.20.21. → Section 7 SCA sweep, Q3
  3. H3 (medium): A package manager installed/updated @injectivelabs around 2026-07-08. → Q2
  4. H4 (medium): @injectivelabs package files were written into node_modules on an endpoint. → Q3
  5. H5 (scoping): Which hosts use the Injective SDK at all (exposure inventory)? → Q4

Attack chain

StepBehaviorTelemetryHunt angle
1GitHub repo compromise; malicious commit under trusted maintainer identityVCS / CI audit logsOIDC + release audit (native)
2Publish backdoored 1.20.21 via OIDC trusted-publisher; pin across 17 scoped packagesRegistry / provenanceSCA registry query (native)
3Downstream npm install pulls 1.20.21 into apps/CIProcessRollup2 / FileCreateInfoInstall activity (Q2), file write (Q3)
4App derives key → fromMnemonic()/fromHex() hooked by trackKeyDerivation()In-process (not observable)GAP — code review / SCA
5Secret base64-encoded, smuggled in X-Request-Id to exfil hostDnsRequest / proxyDNS to exfil host (Q1), header inspection (native)
04

Consolidated IOC Table

Indicators trace to Socket and Datadog Security Labs (both 2026-07-09), corroborated by BleepingComputer and The Hacker News. The exfil host is a lookalike of legitimate Injective infrastructure — validate before global block.

TypeValueConfActionContext
Package@ver@injectivelabs/sdk-ts@1.20.21highdetectPrimary backdoored package (wallet-key stealer)
Exfil hosttestnet.archival.chain.grpc-web.injective[.]networkhighdetectSecrets base64-smuggled in X-Request-Id header
Code markertrackKeyDerivation()highhuntMalicious hook function name
Code markerhook on PrivateKey.fromMnemonic() / fromHex()highhuntKey-derivation exfil hooks (marker "fm")
Clean version@injectivelabs/sdk-ts@1.20.23highenrichSafe rollback target (also 1.20.20 and earlier)
SHA-256103c4e6181151c1bcfedc41506cd1815458c38375d08a8fcd9981dbe0b965ce0highdetectMalicious artifact
SHA-2569a59eb454f3ca3fe91214136ee5edd417cc47a80e6f169b52099d6561944baf9highdetectMalicious artifact

The malicious 1.20.21 pin also affects these 17 scoped packages (full list in Section 10): utils, networks, ts-types, exceptions, wallet-base, wallet-core, wallet-cosmos, wallet-private-key, wallet-evm, wallet-trezor, wallet-cosmostation, wallet-ledger, wallet-wallet-connect, wallet-magic, wallet-strategy, wallet-turnkey, wallet-cosmos-strategy.

05

Affected Surface & Telemetry Matrix

SurfaceRequired telemetryPriorityGap risk
Developer / build workstationsProcessRollup2 (node/npm), FileCreateInfo (node_modules)CriticalMedium — JS file writes are not always captured by EDR
CI/CD runnersBuild logs, registry pulls, provenance attestationsCriticalHigh — runners often outside EDR coverage
Endpoint / egress networkDnsRequest, proxy HTTP logs (headers)HighMedium — header inspection needs a TLS-terminating proxy
Package registry / SCALockfiles, `npm ls`, SBOM, Socket/OSV feedsCriticalLow — this is the authoritative surface
In-process key theftGAP — the mnemonic hook runs inside Node; not endpoint-observable
06

ATT&CK Mapping

TacticTechniqueBehaviorQuery / Control
Initial AccessT1195.002 Supply Chain: Software DependenciesBackdoored npm packageQ2, Q3, SCA sweep
ExecutionT1059.007 JavaScripttrackKeyDerivation() hook runs in NodeGAP (native/code review)
Credential AccessT1552.001 Unsecured Credentials: FilesSteal BIP-39 mnemonics / private keysQ1, rotate keys
CollectionT1005 Data from Local SystemCapture key material at derivationNative / SCA
ExfiltrationT1041 / T1071.001 Exfil over C2 (HTTP header)base64 in X-Request-Id to exfil hostQ1, proxy header hunt
Defense EvasionT1036.005 Masquerading: legit name/locationSigned via OIDC provenance; lookalike exfil hostProvenance verification
07

Native Audit-Log Hunts

For a JS supply-chain compromise the registry/SCA surface is authoritative — run these first, they beat any endpoint query:

  • Lockfile / SBOM sweep (highest fidelity): grep every repo, build image, and artifact cache for 1.20.21 under any @injectivelabs package in package-lock.json, yarn.lock, pnpm-lock.yaml, and SBOMs. Any hit = exposed.
  • Installed tree check: on dev/build hosts run npm ls @injectivelabs/sdk-ts (and the 17 sibling packages) and confirm the resolved version is not 1.20.21.
  • Registry mirror / proxy logs: query your internal npm proxy (Artifactory/Verdaccio/Nexus) for downloads of any @injectivelabs package version 1.20.21 since 2026-07-08.
  • Egress proxy header inspection: if a TLS-terminating proxy is in place, hunt outbound requests to *.grpc-web.injective.network carrying an anomalous X-Request-Id (long base64) header.
  • CI/CD + VCS audit: review GitHub Actions OIDC trusted-publisher config and release history for the Injective SDK repo; verify npm provenance attestations on installed versions; look for release artifacts published in the compromise window.
  • Secrets exposure: enumerate hosts/CI that handle wallet mnemonics or private keys and cross-reference against exposed repos — those keys are compromised.
08

CrowdStrike LogScale CQL Hunt Queries

Pick your tenant's cloud first — every "Open in Falcon" button below uses this selection.

This is a JavaScript supply-chain compromise: the key-theft hook runs inside Node and is not endpoint-observable. The queries below cover the network exfil and install/file artifacts; the authoritative detection is the SCA/lockfile sweep in Section 7. Coverage gaps are flagged in Section 15.

Q1 · DNS / beacon to the backdoor exfil host
CONF HIGHFP MEDCOST LOW

Looks for: any host resolving the exact exfil hostname the backdoor smuggles secrets to. FP: the host mimics real Injective archival infrastructure — a legitimate Injective app could plausibly resolve a sibling grpc-web.injective.network name, so confirm the exact FQDN and correlate with a wallet/DeFi workload before escalating.

// HUNT: DNS to the Injective SDK backdoor exfil host
// MITRE: T1041 / T1071.001 | CONF: high  FP: medium  COST: low | REQUIRES: DnsRequest
// TUNING: match the EXACT FQDN; allowlist known-legit Injective infra endpoints in use by sanctioned apps
#event_simpleName=/DnsRequest/
| DomainName=/^testnet\.archival\.chain\.grpc-web\.injective\.network$/i
| table([ComputerName, aid, DomainName, ContextBaseFileName], limit=200)
Q2 · Package manager installing/updating @injectivelabs
CONF MEDFP MEDCOST LOW

Looks for: a package-manager process whose command line references @injectivelabs — surfaces hosts that pulled the SDK so you can then check the resolved version. FP: legitimate installs of the SDK look identical; treat hits as a triage list, not a detection, and confirm the version via npm ls.

// HUNT: npm/yarn/pnpm install of @injectivelabs (triage list for version check)
// MITRE: T1195.002 | CONF: medium  FP: medium  COST: low | REQUIRES: ProcessRollup2
// TUNING: after a hit, run `npm ls @injectivelabs/sdk-ts` on the host; only 1.20.21 is malicious
#event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/
| FileName=/^(node\.exe|npm\.cmd|npm|yarn|yarn\.cmd|pnpm|pnpm\.cmd)$/i
| CommandLine=/@injectivelabs/i
| table([ComputerName, aid, FileName, CommandLine, ParentBaseFileName], limit=200)
Q3 · @injectivelabs package files written into node_modules
CONF MEDFP MEDCOST LOW

Looks for: writes of @injectivelabs package files into a node_modules tree — evidence the SDK (or a sibling wallet package) was installed on the endpoint. FP: fires for any install of these packages, benign or not; use it to build the exposure list, then confirm the version.

// HUNT: @injectivelabs package files landing in node_modules
// MITRE: T1195.002 | CONF: medium  FP: medium  COST: low | REQUIRES: FileCreateInfo
// TUNING: JS file-write telemetry is partial; pair with Section 7 lockfile sweep for authoritative coverage
#event_simpleName=/FileCreateInfo|NewExecutableWritten/
| TargetFileName=/@injectivelabs\\(sdk-ts|wallet-|utils|networks|ts-types|exceptions)/i
| table([ComputerName, aid, TargetFileName, ContextBaseFileName], limit=200)
Q4 · Injective SDK exposure inventory (all grpc-web.injective.network)
CONF LOWFP HIGHCOST LOW

Looks for: which node/electron processes talk to Injective gRPC infrastructure at all — a scoping query to inventory hosts that use the SDK, not a detection. FP: intentionally broad and matches legitimate Injective apps; use only to bound the population that needs the Section 7 version check.

// HUNT: exposure inventory — node/electron resolving Injective gRPC infra
// MITRE: T1195.002 | CONF: low  FP: high  COST: low | REQUIRES: DnsRequest
// TUNING: scoping-only; do NOT alert on this — feed hits into the lockfile/npm-ls sweep
#event_simpleName=/DnsRequest/
| DomainName=/grpc-web\.injective\.network$/i
| ContextBaseFileName=/^(node\.exe|electron\.exe)$/i
| table([ComputerName, aid, DomainName, ContextBaseFileName], limit=200)
09

CrowdStrike Custom IOA Recommendations

IOA-1 · Beacon to the backdoor exfil host

Type: Network / DNS. Domain (exact): testnet.archival.chain.grpc-web.injective.network. Action: Detect, and block the FQDN at the egress proxy. Exclusion: none — no sanctioned workload should reach this exact host.

The remaining queries are hunt/triage or scoping and are not IOA-promotion candidates — a legitimate SDK install is indistinguishable from a malicious one at the endpoint layer, so the version decision belongs to SCA/registry tooling (Section 7), not a Custom IOA. Promote IOA-1 only.

10

Machine-Readable IOC Appendix

Falcon IOC Management CSVbulk import
type,value,action,severity,expiration,description,tags
domain,testnet.archival.chain.grpc-web.injective.network,detect,critical,2027-01-11,Injective SDK backdoor exfil host,campaign:InjectiveNpm
sha256,103c4e6181151c1bcfedc41506cd1815458c38375d08a8fcd9981dbe0b965ce0,detect,high,2027-01-11,Injective SDK backdoor artifact,campaign:InjectiveNpm
sha256,9a59eb454f3ca3fe91214136ee5edd417cc47a80e6f169b52099d6561944baf9,detect,high,2027-01-11,Injective SDK backdoor artifact,campaign:InjectiveNpm
Poisoned Packages (all @1.20.21)SCA blocklist
@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
# SAFE ROLLBACK: 1.20.23 (or 1.20.20 and earlier)
Behavioral / Code MarkersSCA + code review
hook_fn        = trackKeyDerivation()
hooked_targets = PrivateKey.fromMnemonic()  (marker "fm")
                 PrivateKey.fromHex()
exfil_host     = testnet.archival.chain.grpc-web.injective.network
exfil_channel  = base64 payload in X-Request-Id HTTP header (POST/HTTPS)
window         = 2026-07-08 20:59 - 21:48 UTC (~49 min, ~310 downloads)
delivery       = GitHub OIDC trusted-publisher, trusted maintainer identity
Lockfile Sweep Greprun across all repos
# Find any @injectivelabs package pinned at the poisoned version
grep -rEl "@injectivelabs/[a-z-]+.{0,40}1\.20\.21" \
  --include package-lock.json \
  --include yarn.lock \
  --include pnpm-lock.yaml .
# Any file printed = exposed repo -> remediate + rotate keys
11

Detection Validation Gates

GateCheckPass condition
Telemetry readyDnsRequest + ProcessRollup2 flowing from dev/build hosts; egress proxy logging headersPresent in last 24h
Authoritative sweepLockfile/SBOM grep for @injectivelabs @1.20.21 across all repos + CI imagesZero hits (or all remediated)
Positive testAdd a benign DNS lookup of the exact exfil FQDN in a labQ1 fires within one interval
Exposure boundQ4 inventory reconciled against SBOMEvery SDK-using host version-checked
12

Hardening — Tiered & Deployable

Immediate (this week)
  • Rotate all exposed wallet keys / mnemonics (M1027-adjacent; ⚠ best-practice): any BIP-39 seed or private key handled on a host/CI that resolved 1.20.21 is compromised — rotate and move funds.
  • Purge and roll back the package (M1051 Update Software): force @injectivelabs/sdk-ts and all 17 siblings to 1.20.23 or an earlier clean version; delete 1.20.21 from caches, lockfiles, and CI images.
  • Block the exfil host (M1031 Network Intrusion Prevention): deny testnet.archival.chain.grpc-web.injective.network at the egress proxy/firewall and import the Section 10 CSV to Falcon.
Near term (1–4 weeks)
  • Deterministic, script-free installs in CI (M1016 Vulnerability Scanning; ⚠ best-practice, no formal CIS): use npm ci against a committed lockfile and --ignore-scripts; fail builds on lockfile drift.
  • Continuous SCA (M1016): enable Socket / OSV / Dependabot on every repo and CI pipeline to catch malicious versions at PR time.
  • Verify npm provenance attestations (M1054 Software Configuration): require and check provenance on installed packages; block unverified publishes.
Strategic (1–3 months)
  • Internal package proxy with allowlist (M1016; Artifactory/Verdaccio/Nexus): mirror and vet third-party packages; freeze new versions for a soak window before promotion.
  • SLSA build provenance + signed releases (M1054): enforce provenance-verified, reproducible builds across the pipeline.
  • Isolate key material to hardware (M1027-adjacent; ⚠ best-practice): move signing to hardware wallets/HSMs so an SDK compromise cannot read a raw mnemonic in process memory.
13

Deployable Playbooks

Playbook A — Remediate the poisoned dependency (bash / npm)

# 1. Sweep every repo for the poisoned pin
grep -rEl "@injectivelabs/[a-z-]+.{0,40}1\.20\.21" --include '*lock*' .

# 2. Pin to a clean version and rebuild deterministically
npm pkg set dependencies.@injectivelabs/sdk-ts=1.20.23
rm -rf node_modules package-lock.json
npm install --ignore-scripts
npm ci

# 3. Purge the poisoned version from the local + CI cache
npm cache verify
npm cache clean --force

Playbook B — Block exfil host + confirm no beacons (bash)

# Proxy/firewall: deny the exact exfil FQDN
# (example: add to blocklist ACL, then verify no host has resolved it)
echo "testnet.archival.chain.grpc-web.injective.network" | tee -a /etc/proxy/blocklist.d/injective-npm.txt
# Then run HuntPack Q1 in Falcon to confirm zero resolutions fleet-wide.

Playbook C — CI hardening (workflow policy)

# package.json - enforce clean, script-free installs
npm pkg set scripts.preinstall="echo use npm ci"
# CI step: install with a frozen lockfile and no lifecycle scripts
npm ci --ignore-scripts
# Enable SCA gate (example: Socket / OSV) as a required status check on PRs
# Require npm provenance verification before promotion to the internal proxy
14

Containment Runbook

PhaseActionsOwnerEvidence
ScopeLockfile/SBOM sweep for @injectivelabs @1.20.21 across repos, CI, and dev hosts (Section 7)AppSecList of exposed repos/hosts
ContainBlock the exfil FQDN at egress; freeze affected pipelines; halt deploys built in the compromise windowSOC / PlatformProxy deny entry, pipeline hold
RotateTreat every wallet key/mnemonic touched by an exposed app as compromised — rotate keys, move funds, revoke API/publish tokensCrypto Ops / IAMKey-rotation log
EradicateRoll all @injectivelabs packages to 1.20.23; purge 1.20.21 from caches/lockfiles; rebuild with npm ci --ignore-scriptsDev teamsClean lockfile diff
RecoverRe-enable pipelines with SCA + provenance gates; confirm Q1 returns zero beacons; audit GitHub OIDC/release configPlatformGreen SCA run, clean Q1
15

Detection Coverage Map

TechniqueBehaviorCQLIOA / NativeCoverage
T1041 / T1071.001Exfil to backdoor hostQ1IOA-1 + proxy blockGood
T1195.002Poisoned package present (version)Q2, Q3SCA / lockfile sweepPartial (CQL) / Good (SCA)
T1059.007trackKeyDerivation() hook executionCode review / SCAGap
T1552.001Mnemonic/private-key theft in processKey rotation (assume compromise)Gap
T1036.005OIDC provenance abuseVCS/CI auditPartial
SDK exposure inventoryQ4SBOM reconcileScoping

Known gaps (honest): the actual key theft and the trackKeyDerivation() hook run inside Node and are not endpoint-observable — there is no CQL that proves theft occurred, so the response model is "assume compromise and rotate." Endpoint queries (Q2/Q3) only build an exposure list; the authoritative detection is the SCA/lockfile sweep in Section 7. Validation gates (Section 11) must pass before relying on this coverage.

16

Hunt Summary Ticket

TITLE:      Injective Labs npm supply-chain — @injectivelabs/sdk-ts@1.20.21 wallet stealer
SEVERITY:   Critical — crypto key/mnemonic theft via backdoored dependency
SCOPE:      Dev/build workstations, CI runners, and repos using @injectivelabs packages
HYPOTHESIS: Poisoned 1.20.21 hooks fromMnemonic()/fromHex(), exfils secrets base64
            in X-Request-Id header to testnet.archival.chain.grpc-web.injective.network.
QUERIES:    Q1 exfil DNS · Q2 pkg-mgr install · Q3 node_modules write · Q4 exposure inv
DO FIRST:   Lockfile/SBOM sweep for @injectivelabs @1.20.21 (Section 7); block exfil FQDN
FINDINGS:   ____ exposed repos  ____ hosts w/ 1.20.21  ____ exfil beacons
GAPS:       In-process key theft = not endpoint-observable -> ROTATE KEYS (assume compromise)
ACTIONS:    Roll to 1.20.23, purge caches, rotate wallet keys + publish tokens, audit OIDC
OWNER:      __________            VERSION: v0.2 · 2026-07-11
17

Changelog

v0.22026-07-24CQL correctness pass. All table() calls now carry an explicit row limit: the default is 200 and truncation is silent, so a capped result was indistinguishable from a complete one. Atomic-IOC sweeps (filters over 5+ hashes or C2 IPs) use limit=max so a wide infection is never silently under-scoped; behavioural hunts use limit=200, where exceeding the cap indicates the query needs tuning. Where present, event names that do not exist in the Falcon data model were corrected (e.g. ServiceInstalled is a Sysmon concept, not a Falcon event; ElfFileWritten is ELFFileWritten) — such queries could never return a row. No detection logic, fields, or IOCs changed.
v0.12026-07-11Initial HuntPack — 4 CQL queries (1 IOA candidate), authoritative SCA/lockfile hunts, full poisoned-package list (18 packages), exfil host + hashes from Socket + Datadog + BleepingComputer + The Hacker News, tiered supply-chain hardening + playbooks + containment runbook.
18

References

TierSourceUsed ForAccess Date
1Socket — Compromised Injective SDK npm Package (2026-07-09)Package list, exfil endpoint, hooked functions, hashes2026-07-11
1Datadog Security Labs — sdk-ts Backdoor (2026-07-09)X-Request-Id exfil, timeline, versions2026-07-11
2BleepingComputer — Injective SDK infected with wallet stealer (2026-07-09)Downloads, repo compromise, deprecation status2026-07-11
2The Hacker News — Injective Labs GitHub Compromise (2026-07-09)OIDC abuse, transitive packages2026-07-11
3MITRE ATT&CKTechnique IDs and mitigations (M-numbers)2026-07-11