# jscrambler npm package publishes malicious preinstall binary

Compromised jscrambler npm releases shipped a preinstall hook dropping a Rust native binary that steals browser credentials and crypto wallet vaults.

- Payout: Real-world hack
- Severity: critical
- Program: jscrambler
- Analysis by: StepSecurity
- Disclosed: 2026-07-12
- Write-up quality: 8/10
- Original: https://www.stepsecurity.io/blog/jscrambler-npm-package-publishes-malicious-preinstall-binary
- Library page: https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-jscrambler-npm-package-publishes-malicious-preinstall-binary
- Tags: area:oss domain:oss impact:data-leak impact:funds-loss kind:incident platform:threat-intel sev:critical tech:nodejs technique:reverse-engineering technique:source-review vuln:secrets-leak

**Target:** npm package (jscrambler CLI) install/require path
**Root cause:** Attacker published compromised versions of the jscrambler npm package adding a preinstall hook (later inlined into dist/index.js) that parses a 7.8 MB fake dist/intro.js container with magic header 1B 43 53 49 01, decompresses a platform-matched native binary to a temp dotfile, and spawns it detached.
**Steps:**
1. Compare 8.14.0 tarball (7.9 MB) against clean 8.13.0 (37.8 kB); note new `preinstall` script in package.json
2. Inspect dist/intro.js: 7.8 MB non-JS file with 5-byte magic header `1B 43 53 49 01`, per-platform entries (platform-id byte, 8-byte size, 8-byte LE compressed size, gzip data)
3. Loader selects entry by `process.platform`, decompresses to random dotfile in OS temp dir (`.exe` on Windows), chmod +x, spawns detached and unref'd
4. In 8.18.0/8.20.0 the same loader is inlined as IIFE at top of dist/index.js, firing on `require('jscrambler')` with no install hook
5. Static analysis of binaries: embedded SQLite (FTS3/FTS4), LevelDB, BIP39 wordlist; Linux imports libbpf (`bpf_object__open_mem`, `bpf_object__load`, `bpf_program__attach`), Windows imports IsDebuggerPresent and GetExtendedTcpTable, macOS imports sysctl/sysctlbyname
**How found:** StepSecurity's OSS AI Package Analyst flagged the release with suspicion score 0 (the maximum) on publish; analysts then diffed tarball size, file count, package.json and dist/ contents against the last clean 8.13.0 and inspected the anomalous 7.8 MB dist/intro.js.
**Exploitation:** On npm install (or require for gen 2), the loader drops and detaches a native stealer that reads Chrome/Firefox Login Data, Cookies, Web Data, key4.db and Chromium Local Storage/IndexedDB (MetaMask vault), with eBPF kernel instrumentation on Linux; Harden-Runner observed outbound calls to archive.torproject.org, check.torproject.org, 37.27.122.124, 57.128.246.79.
**Escalation:** Inlining the loader into dist/index.js removed the install-hook signal, triggering on any import in CI/CD or app code; detached/unref'd process survives npm install exit; kernel-level eBPF and anti-debug imports raise capability beyond typical stealers.
**Insight:** Diff tarball size and file inventory against the prior clean release — a 200x size jump and a large non-JS file with a .js extension (custom magic header) is a strong supply-chain signal; also check dist/index.js top-level IIFEs, since attackers move payloads out of install hooks into require-time code to evade hook-only scanners.

