Feed
CriticalPublished 11 Jul 20261 package · 5 versions

Official `jscrambler` npm package compromised — 5 malicious releases drop a cross-platform Rust infostealer (Chrome/Brave/Edge/Chromium profiles, Bitwarden vault, Steam sessions, cloud metadata, MetaMask/Phantom/Exodus wallets)

Summary

On 2026-07-11 15:12 UTC the official jscrambler npm package was hijacked via the jscrambler_ maintainer account. Five malicious releases (8.14.0, 8.16.0, 8.17.0, 8.18.0, 8.20.0) shipped a Rust infostealer that harvests Chromium browser profiles, the Bitwarden vault, Steam sessions, AWS/Azure/GCP credentials, and MetaMask/Phantom/Exodus wallet seeds.

maintainer-takeoveraccount-takeoverinfostealercredential-theftcrypto-wallet-drainobfuscation
Detected by
Socket · SafeDep · StepSecurity · Snyk
Also known as
Scavenger infostealer · jscrambler 8.14.0 compromise
Ecosystems
npm
Packages tracked
1

What happened

On 2026-07-11 at 15:12 UTC the official jscrambler npm package — the JavaScript client for the Jscrambler code-integrity platform — was hijacked. Over the next ~3 hours the attacker pushed 5 malicious releases from the legitimate jscrambler_ maintainer account, interleaved with clean releases the Jscrambler maintainers appear to have pushed as remediation. Socket, StepSecurity, SafeDep, and Snyk all published write-ups within 24 hours.

Release timeline

| Version | Publish (UTC, 2026-07-11) | Dropper location | Registry state at write-up | |---|---|---|---| | 8.14.0 | 15:12 | preinstalldist/setup.js → unpacks dist/intro.js | deprecated as compromised | | 8.15.0 | 17:07 | clean (maintainer remediation) | published | | 8.16.0 | 17:26 | preinstalldist/setup.js | deprecated as compromised | | 8.17.0 | 17:41 | preinstalldist/setup.js | deprecated as compromised | | 8.18.0 | (within 3h window) | runtime in dist/index.js + dist/bin/jscrambler.js — no preinstall | still published, NOT deprecated | | 8.20.0 | (within 3h window) | runtime in dist/index.js + dist/bin/jscrambler.js | still published, NOT deprecated | | 8.22.0 | (post-remediation) | clean | current latest |

Socket flagged 8.14.0 six minutes after publish; the take-down window before deprecation was measured in tens of minutes for the earliest versions but stretched significantly for the runtime-dropper builds.

Payload — cross-platform Rust infostealer

Every malicious release ships the same native dropper. dist/setup.js (or the runtime-load equivalent) is a small loader; dist/intro.js — despite the extension — is a ~7.8MB container packing three gzip-compressed native binaries, one each for Linux, Windows, and macOS. The loader matches the target platform, extracts the appropriate binary, and detaches it as a background process.

The stealer itself is a Rust-compiled infostealer that has been informally attributed to the Scavenger family based on Rust artefact and target-list matching. It targets:

  • Browser profile data — Chrome, Brave, Edge, and Chromium — including cookies, saved passwords, autofill, and session data
  • Bitwarden browser extension — vault export via the extension's local storage
  • Steam — session tokens and login data
  • Cloud credentials — AWS access keys and STS tokens, Azure token cache, GCP application default credentials, plus the AWS/GCP/Azure metadata endpoints (169.254.169.254) so a compromised CI runner leaks its instance-role identity
  • Crypto wallets — MetaMask, Phantom, and Exodus browser-extension / desktop wallet profiles (seed phrases and encrypted key stores)
  • Persistence — Windows Task Scheduler entries on Windows and ~/Library/LaunchAgents/ plists on macOS, so the stealer re-runs after reboot

Exfiltration is TLS to a drop server. The C2 endpoint is not visible in plain strings — the binary decrypts its configuration at runtime using embedded AES / ChaCha20 primitives, which is why publicly-shared IOCs do not yet include a clean host list.

8.18.0 — the runtime dropper bypass

The most significant part of this compromise is the 8.18.0 pivot. npm 12 shipped on 2026-07-08 (three days before the compromise) with dependency install scripts disabled by default — a long-anticipated hardening step that neuters preinstall/postinstall hooks unless the user explicitly approves them. On npm 12, 8.14.0/8.16.0/8.17.0 install cleanly without executing the payload.

At 8.18.0 the attacker moved the dropper out of the preinstall hook and into the package's own dist/index.js and dist/bin/jscrambler.js, so it runs when the module is required — i.e. every time a downstream build or CLI loads jscrambler at runtime. This defeats npm 12's new default, --ignore-scripts, and any hardening that only inspects install-time hooks. A CI job that pins jscrambler@8.18.0 and passes --ignore-scripts is still fully compromised the moment require('jscrambler') executes.

This is the first known npm compromise where the attacker deliberately pivoted mid-campaign to defeat the npm 12 install-script default. Expect the pattern to become standard.

Attribution

No commit, tag, or release for any of the malicious versions exists in the jscrambler/jscrambler GitHub repository — the malicious tarballs were built and uploaded straight to npm under the legitimate jscrambler_ maintainer account. That points to a compromised npm account or build pipeline, not a source-tree tamper. The Jscrambler organisation has not published an official postmortem at time of write.

Detection window

Socket detected 8.14.0 six minutes after publish and issued its advisory. StepSecurity, SafeDep, Snyk, and The Hacker News all had write-ups live within 24 hours. 8.14.0, 8.16.0, and 8.17.0 were deprecated by npm as compromised; 8.18.0 and 8.20.0 were still live on the public registry at time of write. Because those two runtime-dropper versions remain published, any semver-based resolver against a stale lockfile can still land on live malware today.

Affected packages (1)

  • npmjscrambler
    8.14.08.16.08.17.08.18.08.20.0

Impact

  • Any host that ran npm install jscrambler@{8.14.0,8.16.0,8.17.0,8.18.0,8.20.0} should be treated as fully compromised — the payload runs at install time (8.14.0/8.16.0/8.17.0 via preinstall hook) or at module-require time (8.18.0/8.20.0)
  • Credentials at risk: AWS/Azure/GCP cloud credentials including the metadata endpoints CI runners use; Bitwarden browser-extension vault; browser-stored credentials from Chrome, Brave, Edge, and Chromium profiles; Steam session tokens
  • Wallet drain: MetaMask, Phantom, and Exodus wallet extensions — seed phrases and private keys
  • Persistence: Windows Task Scheduler entries and macOS LaunchAgents survive reboot; the Rust binary keeps beaconing after the first exfil
  • Attack vector: the malicious versions were published under the legitimate jscrambler_ maintainer account with no matching commit/tag/release in the jscrambler/jscrambler GitHub repository, pointing to a compromised npm account or CI publish pipeline — the source tree is not implicated
  • 8.18.0 dropped the preinstall hook and moved the dropper into dist/index.js and dist/bin/jscrambler.js, so it runs when your code loads the module (i.e. every time you run your build/CLI, not just npm install). This defeated npm 12's new install-script sandbox (npm 12 shipped 2026-07-08 with install scripts off by default) and bypassed any hardening based on --ignore-scripts / preinstall denylists
  • Registry state as of write-up: 8.14.0, 8.16.0, and 8.17.0 were deprecated by npm as compromised; 8.18.0 and 8.20.0 remain published and NOT deprecated — a lockfile pin against those two still resolves malware today. latest is now 8.22.0 (clean)

What to do

  1. 1Grep every lockfile for jscrambler — pin only >=8.22.0 (the clean release; latest at write-up) or <=8.13.x (last confirmed-clean before the compromise window)
  2. 2If you installed any of 8.14.0, 8.16.0, 8.17.0, 8.18.0, 8.20.0 on a developer workstation: assume every browser-stored credential, Bitwarden vault, MetaMask/Phantom/Exodus seed, and Steam session token is captured. Rotate from a different machine and re-image the affected host
  3. 3If you installed any of the compromised versions on a CI runner: assume AWS/Azure/GCP credentials reachable from the runner (including instance metadata) are captured. Rotate cloud creds, revoke long-lived IAM keys, and audit CloudTrail / activity logs for the exposure window
  4. 4Remove persistence artifacts: check Windows Task Scheduler for unfamiliar tasks; check ~/Library/LaunchAgents/ on macOS for unexpected plists; check ~/.config/systemd/user/ on Linux
  5. 5Do NOT rely on --ignore-scripts to have protected you — the 8.18.0 and 8.20.0 versions ship the dropper in dist/index.js and dist/bin/jscrambler.js, which run at module-load time, not install time. --ignore-scripts blocks the preinstall path for 8.14.0/8.16.0/8.17.0 but does nothing for the runtime droppers
  6. 6Flush internal Artifactory / Nexus / Verdaccio caches — these mirrors will keep serving the malicious tarballs long after the public deprecation
  7. 7Because 8.18.0 and 8.20.0 are STILL published as of the write-up, semver ranges like ^8.14.0 or ~8.18 on a stale lockfile will resolve to malware on the next npm install. Pin the exact 8.22.0 (or newer clean release) in your lockfile now
  8. 8If you are the maintainer of a downstream package that depends on jscrambler: bump your minimum to >=8.22.0 and publish an advisory bump so consumers stop resolving the compromised range

References

npm-2026-07-11-jscrambler-rust-infostealer