Home/ Blog/ Security news/ Article
Blog · Security news

npm just killed install-script malware by default. This week's other attack walks right past it.

npm 12 disables install scripts by default, which would have stopped this week's jscrambler infostealer. The Injective Labs package compromise shows exactly

Two sealed crates on a conveyor belt passing a scanning arch

Two npm package compromises landed in the same week that npm shipped the one default change built to stop them. The timing is the story. On July 11 a poisoned release of the jscrambler package ran an infostealer the moment developers installed it. Three days earlier, a compromised Injective Labs package quietly began lifting cryptocurrency keys from anyone whose code used it. npm 12, released the same week, now disables install scripts by default. That kills the jscrambler attack outright. It does nothing to the Injective one, and the reason it cannot is the more useful lesson here.

The same registry, two very different attacks

The jscrambler npm package is a widely used JavaScript obfuscation tool, and its download counter sits around 15,800 a week. On July 11 a booby-trapped 8.14.0 went out. During installation a hook chose the right native binary for whatever operating system it landed on, dropped it into a temporary folder under a randomized filename, made it runnable, and started it in the background. The binary was an infostealer written in Rust, with builds for Windows, macOS, and Linux. Once running, it raided cloud-provider credentials, saved browser logins and cookies, several cryptocurrency wallets, chat-app session tokens, and even the config files of popular AI coding assistants. A monitoring firm, Socket, spotted the bad version roughly six minutes after it reached the registry. Remediation is blunt: get off 8.14.0, either forward to 8.15.0 or back to the clean 8.13.0, and rotate every secret that machine could touch.

The Injective Labs case is quieter and, for a defender, harder. On July 8, @injectivelabs/sdk-ts version 1.20.21 shipped with malicious code introduced through a commit from a GitHub account belonging to an established maintainer, then published through the project's trusted-publisher pipeline. According to reporting from Socket and OX Security, the malware never touched an install hook. Instead it rewrote the SDK's real key-derivation routines so that every time a wallet key was produced, a bogus telemetry call skimmed the private key and recovery phrase and shipped them to a server dressed up as an Injective subdomain. Seventeen more @injectivelabs packages were poisoned the same way, some of them wallet libraries that other projects pull in transitively. The fix is version 1.20.23, and every key handled by the bad version should be treated as exposed. This is the same shape we saw when packages that passed inspection turned hostile a day later: the registry entry looks fine, the behavior is not.

 jscrambler 8.14.0Injective sdk-ts 1.20.21
Entry pointMalicious preinstall hookCommit from a trusted maintainer, published via OIDC
When the code runsAt npm installAt runtime, whenever the SDK is used
What it stealsCloud, browser, wallet, chat, and AI-tool dataWallet private keys and seed phrases
Stopped by npm 12 default?YesNo
FixMove to 8.15.0 or pin 8.13.0Upgrade to 1.20.23, rotate all keys
Source: Socket, OX Security, The Hacker News, and BleepingComputer reporting.

What npm 12 changes, and what it does not

npm 12, out from GitHub the same week, inverts the setting that made the jscrambler attack work. By default it no longer runs the hooks a package registers to fire during installation, the preinstall, install, and postinstall steps, nor the automatic native builds that node-gyp kicks off. Dependencies pulled straight from Git or a remote URL are refused too unless a project opts in. When a build step is genuinely needed, a maintainer approves it with npm approve-scripts and checks the resulting allowlist into the repo, so the grant shows up in version control instead of firing silently on every machine. GitHub also started deprecating granular access tokens that sidestep two-factor authentication, and is nudging automated publishing toward trusted publishing over OIDC.

That default would have stopped jscrambler cold. A stealer that only runs from a preinstall hook cannot run if the hook never fires. It would have done nothing about Injective. The malicious code there was not in a lifecycle script; it sat inside a function the application calls on purpose, so it runs whenever the SDK is used, install scripts on or off. Worse, the Injective package reached the registry through the exact trusted-publisher OIDC path npm is now recommending, riding the identity of a real maintainer. We have watched this move before: a free GitHub account can end up pushing code as a trusted maintainer. Trusted publishing does not remove the trust boundary. It relocates it onto the security of maintainer accounts and their commit history, which is a harder thing to watch than an install hook.

Two attacks, two detection problems

These incidents split cleanly along a line worth internalizing. Install-hook malware is loud: it spawns a process, writes a file, and reaches out to the network during npm install, which is exactly why Socket caught jscrambler in six minutes and why npm 12's default helps. Runtime-embedded malware in a trusted package is quiet: no new process at install, no unusual file, just a legitimate function doing one extra thing. This is the same reason opening a poisoned npm project in your editor can be enough to run it. Dependency scanning that inspects a package at install time will not see the Injective payload. Catching that class means watching what your build and application processes actually do at runtime, not just what your lockfile lists. Teams that self-host and can see process and network behavior on their own machines have the vantage point where this kind of compromise surfaces, which is the same discipline behind ongoing threat hunting.

Turn off install scripts now, then watch the maintainers you trust

You do not have to wait for npm 12 to reach your toolchain. Disable install scripts today with npm install --ignore-scripts, or set it in your project config, and add an explicit allowlist for the few dependencies that truly need a build step. Pair it with a release-age delay: Socket needed only six minutes to catch jscrambler, so a policy that refuses to pull any version less than a day or two old would have kept most consumers clear of it with no manual work. That single control blunts the entire loud install-hook class, the one that ships fast and gets caught fast.

For the Injective class, the controls are different. Pin dependencies to hashes so a re-published version cannot silently swap in, review the commit history behind a version bump on any package that touches keys, money, or credentials, and treat maintainer-account compromise as a live threat rather than a rare one. The uncomfortable part is that a trusted maintainer pushing signed, OIDC-published code is doing everything the supply-chain playbook asks. When that account is the thing that is compromised, as a poisoned but trusted vendor script has already shown, the fix is not a better default. It is knowing what your dependencies do once they are running.

Topics

Frequently asked questions

Which npm packages were compromised this week?

Two projects: the jscrambler package version 8.14.0 and @injectivelabs/sdk-ts version 1.20.21, plus 17 related @injectivelabs packages. According to Socket and OX Security, a compromised jscrambler release ran an infostealer at install time, and the poisoned Injective packages skimmed cryptocurrency private keys and seed phrases from inside legitimate SDK functions.

Does npm 12 stop these supply-chain attacks?

Only partly. npm 12 disables package install scripts by default, which would have blocked the jscrambler infostealer that ran from a preinstall hook. It cannot stop the Injective compromise, whose malicious code ran from a normal function at runtime, not from an install script.

How do I disable npm install scripts?

Run installs with npm install --ignore-scripts, or set ignore-scripts in your project or CI configuration. Add an explicit allowlist for the few dependencies that genuinely need a build step. On npm 12 this is the default, and approved scripts are committed via npm approve-scripts.

What is trusted publishing and does it prevent package compromise?

Trusted publishing lets a package be published through an OIDC pipeline tied to a maintainer identity, without a long-lived token. It reduces token theft, but it does not stop a compromised maintainer account. The Injective package was published through exactly this path.

How do I know if the jscrambler infostealer hit me?

Check whether jscrambler 8.14.0 was installed on any machine or build runner since July 11. If it was, assume cloud credentials, browser secrets, wallets, and messaging tokens on that host are exposed. Rotate all of them, revoke sessions, and move any cryptocurrency held there.

Ready to meet the Guardians?

Deploys fast - agentless for monitoring and cloud, a lightweight agent for deep endpoint security. Just Suriq, standing watch.