Skip to content

Back to the catalog

jscrambler npm Package Compromised in Supply Chain Attack
socket.devwriteup

jscrambler npm Package Compromised in Supply Chain Attack

Socket's research team documents a supply chain compromise of the jscrambler npm package (v8.14.0+), where a stolen publishing credential was used to push malicious releases that drop platform-specific Rust-built infostealer binaries via a preinstall hook. The campaign evolved over the incident to evade scanners by moving the dropper from install scripts into a self-executing function inside index.js/CLI code (defeating --ignore-scripts), and the payload targets crypto wallets, cloud credentials (AWS/GCP/Azure), browser data, Discord/Slack/Telegram, and notably AI coding assistant configs (Claude Desktop, Cursor, Windsurf, VS Code) for MCP server credentials. Includes detailed RE of the ChaCha20-Poly1305 string-encryption scheme and full IOC hash list.

TL;DR A compromised jscrambler npm release (and four follow-ups) dropped Rust infostealers targeting crypto wallets, cloud creds, and AI-assistant MCP configs, evolving mid-campaign to evade preinstall-hook scanners.
Document

What it is

A supply chain compromise of the jscrambler npm package (~15,800 weekly downloads), used to integrate Jscrambler's JS code-protection tooling into build/CI pipelines. An attacker with a stolen npm publishing credential shipped a Rust-built cross-platform infostealer across several releases starting July 11, 2026. Jscrambler has confirmed the unauthorized publication in its security advisory and rotated the credential.

Version boundaries (the actionable part)

The malicious payload (the intro.js CSI blob and its three OS binaries) is byte-for-byte identical across every bad release. Only delivery changed:

  • 8.14.0, 8.16.0, 8.17.0 — dropper runs via "preinstall": "node dist/setup.js".
  • 8.18.0, 8.20.0 — install hook removed; identical dropper injected as a self-executing function at the top of dist/index.js and dist/bin/jscrambler.js, so it fires on import or CLI run. This defeats scanners that only inspect install scripts and survives npm install --ignore-scripts. These two also declare a self-dependency ("jscrambler": "^8.17.0"), pulling a compromised release transitively.
  • 8.15.0 — clean interim release. 8.22.0 — latest, clean, safe.

Upgrade to or pin 8.22.0. Do not assume --ignore-scripts protected you on 8.18.0+.

How the dropper works

setup.js reads dist/intro.js — not JS, but a ~7.8 MB container with a 5-byte header 1b 43 53 49 01 (\x1bCSI\x01), sixth byte = payload count. It holds three gzip'd binaries (Linux x86-64 ELF, Windows x86-64 PE, macOS arm64 Mach-O). It selects the blob matching process.platform, decompresses to a randomly named hidden file in the system temp dir (.exe on Windows), marks it executable, and launches it spawn(..., { detached: true, stdio: 'ignore', windowsHide: true }) then unref(). Exfiltration is over TLS (rustls) via a literal POST /upload HTTP/1.1 multipart body.

What to do

Per Socket's recommendation and the version analysis:

  • Remove any affected release; upgrade to or pin 8.22.0.
  • Rotate all credentials reachable from affected workstations/CI: env vars, build credentials, deployment tokens, and specifically the payload's targets — cloud creds (AWS Secrets Manager/SSM, GCP service accounts, Azure IMDS), crypto wallet seeds, Discord/Slack/Telegram, browser data, and AI-assistant MCP configs (Claude Desktop, Cursor, Windsurf, Zed, VS Code).
  • Review install/run logs for execution of dist/setup.js.
  • Audit any machine that installed a bad release for the temp-dir hidden binary, sudo -S -p / systemd-run --no-ask-password privilege-escalation attempts, and persistence via systemd units, crontab, or macOS LaunchAgents.

Decompressed payload SHA-256: Linux fbbcf4d8f98168f78f5c0c47a9ae56d59ec8ac84a7c9ca6b797fedfb8d62d2bd, Windows b7ca95d1b23c8e67416a25cedf741de0917c2096bbc9d24649eea7853d054903, macOS c8fd47d36bdf7c825378593ab82ed8c24d1dc52e26b507812393e24e1d5201fd. Tracking issue: jscrambler/jscrambler#322.

Caveats

The number of users who pulled a compromised version is not yet known. Socket detected 8.14.0 six minutes after publication, but the actor published four more releases over ~3 hours interleaved with remediation attempts, so a machine could have caught a bad version during that window even while fixes were landing.

Technologies named here

Techniques named here

  • Malicious npm preinstall hook
  • Self-executing dropper injected into package code
  • Transitive self-dependency pinning
  • Payload hidden in obfuscated custom container format
  • Platform-selective payload deployment
  • Detached background process execution
  • Per-string ChaCha20-Poly1305 encryption for obfuscation
  • Cloud metadata service credential theft
  • Cryptocurrency wallet vault/seed decryption
  • Local privilege escalation via sudo/systemd-run
  • Persistence via systemd units, crontab, LaunchAgents
  • Anti-analysis and host fingerprinting
  • Exfiltration over TLS via rustls

Threat actors named here