Threat actors compromised Jscrambler's npm publishing credentials and pushed five malicious versions of the jscrambler package between 15:12 and 17:53 UTC on July 11, 2026. The payload — a cross-platform Rust infostealer concealed in a binary container with a .js extension — harvests credentials from development environments, cloud platforms, AI tools, and cryptocurrency wallets. The attack unfolds in two technical generations: the first leverages preinstall hooks; the second — published three days after npm 12 disabled install scripts by default — triggers via require(), bypassing the new mitigation.
- Five malicious versions (8.14.0, 8.16.0, 8.17.0, 8.18.0, 8.20.0) published in roughly three hours, with clean version 8.15.0 interposed — a pattern suggesting manual operator control.
- The payload is a 7.8 MB native Rust binary (ELF, PE32+, Mach-O), not JavaScript, disguised as a .js file behind a custom 5-byte magic header.
- Generation 2 (8.18.0, 8.20.0) bypasses
npm install --ignore-scriptsby inlining the dropper indist/index.js, activated on firstrequire(). - eBPF capability on Linux for kernel-level hooks without touching the filesystem; persistence via scheduled task on Windows and LaunchAgent on macOS.
How the Compromise Happened
The root cause is confirmed: compromised npm publishing credentials, subsequently revoked by Jscrambler. According to the company statement reported by BleepingComputer, the incident is "limited to that package" and did not affect other products, including Webpage Integrity. The malicious versions have no correspondence in the public GitHub repository: no commit, tag, or pull request documents their release. Socket detected version 8.14.0 six minutes after publication; StepSecurity's OSS AI Package Analyst assigned the maximum suspicion score (0) at the moment of publish.
Exact timestamps reconstructed by StepSecurity show a tight sequence: 8.14.0 at 15:12, 8.16.0 at 17:26, 8.17.0 at 17:41, 8.18.0 at 17:46, 8.20.0 at 17:53 UTC. The roughly three-hour window and the presence of clean version 8.15.0 between 8.14.0 and 8.16.0 indicate an operator actively controlling the process, not an automated continuous-release system. Jscrambler's own advisory listed four versions, omitting 8.18.0 — an unexplained discrepancy.
"The payload is not embedded JavaScript. It is a native binary compiled in Rust... smuggled inside a file with a .js extension behind a custom 5-byte magic header." — StepSecurity
Payload Architecture: A Multi-Platform Binary Container
The file dist/intro.js in malicious versions weighs 7.8 MB versus 37.8 kB for the clean version. Behind the .js extension lies a gzip container holding three native binaries: ELF x86-64 for Linux, PE32+ for Windows, Mach-O arm64 for macOS. The magic header 1B 43 53 49 01 — identical byte-for-byte across all five versions — allows the setup.js dropper to identify and decompress the correct payload for the target host.
Once extracted, the binary is written to a temporary directory with a random name and executed in detached mode. The three SHA-256 hashes documented by The Hacker News and StepSecurity are: Linux fbbcf4d8f98168f78f5c0c47a9ae56d59ec8ac84a7c9ca6b797fedfb8d62d2bd; Windows b7ca95d1b23c8e67416a25cedf741de0917c2096bbc9d24649eea7853d054903; macOS c8fd47d36bdf7c825378593ab82ed8c24d1dc52e26b507812393e24e1d5201fd.
The Dual Generation: From preinstall to require()
The first three versions (8.14.0–8.17.0) represent generation 1: activation occurs via the preinstall field in package.json, executed automatically during npm install. This is the classic npm supply-chain technique, now mitigated by npm 12, released July 8, 2026, with install scripts disabled by default.
Generation 2 (8.18.0–8.20.0) responds to that hardening. The dropper is inlined directly into dist/index.js, the package's main entry point, and triggers on the first require("jscrambler") — an operation that necessarily occurs when the module is imported into the target application. As The Hacker News and StepSecurity note, npm install --ignore-scripts does not stop this variant: the malicious code already resides in the module's primary file.
The three-day gap between npm 12 and the attack is not coincidental. The operator observed the default change, verified that legacy clients remained vulnerable to preinstall hooks, and simultaneously prepared a variant resistant to the new configuration. The speed of adaptation signals operational maturity.
What It Steals and How It Persists
The infostealer targets credentials across multiple attack surfaces. Targets documented by BleepingComputer, The Hacker News, and Security Boulevard include: development environments (Git, SSH, environment variables, CI/CD tokens); cloud platforms (AWS, Azure, GCP, Kubernetes); AI tools (Claude, Cursor, Windsurf, VS Code, Zed) with MCP (Model Context Protocol) configurations; cryptocurrency wallets (MetaMask, Phantom, Coinbase, Exodus, Trust); enterprise messaging (Slack, Discord, Telegram); and the Bitwarden password manager.
The eBPF capability on Linux, identified by StepSecurity via import-table analysis, is particularly significant. The payload links libbpf.so.1 and uses bpf_object__open_mem, bpf_object__load, and bpf_program__attach to load eBPF programs directly from memory, without writing to the filesystem. This enables kernel-level hooks with minimal forensic trace. On Windows, persistence occurs via a hidden scheduled task relaunching every minute; on macOS via a LaunchAgent in ~/Library/LaunchAgents. Both platforms implement anti-debug: IsDebuggerPresent on Windows, sysctl/sysctlbyname with P_TRACED on macOS.
Network indicators observed by StepSecurity with Harden-Runner include outbound calls to archive.torproject.org and check.torproject.org, plus IPs 37.27.122.124 and 57.128.246.79. Exfiltration occurs over TLS through the Tor network.
What to Do Now
StepSecurity issued the clearest operational guidance: "If you have installed any of jscrambler versions 8.14.0, 8.16.0, 8.17.0, 8.18.0, or 8.20.0: treat the host as compromised." This recommendation translates into four priorities.
First: check lockfiles (package-lock.json, yarn.lock, pnpm-lock.yaml) for the five malicious versions. Version 8.15.0 is clean; 8.22.0 is the version sources recommend as clean.
Second: on systems where a compromised version executed, perform a full rotation of all credentials in the target categories listed by the sources — not just npm, but also Git, cloud, CI/CD, AI tools, and cryptocurrency wallets.
Third: check for OS-level persistence: undocumented minutely scheduled tasks on Windows, and LaunchAgents in ~/Library/LaunchAgents on macOS. Outbound network analysis toward the indicated Tor domains and IPs can confirm active compromise.
Fourth: verify that CI/CD pipelines do not reuse caches or artifacts derived from builds with the malicious versions. The payload activates on require(): a container image built with the compromised package remains infected even if the lockfile is later corrected.
The Paradox of a "Code Integrity" Vendor
Jscrambler sells client-side protection and code-integrity products. The fact that its own npm package became the vector for one of 2026's most sophisticated supply-chain attacks — with active adaptation to freshly released mitigations — raises questions about the trust model that security toolchains demand of developers. No vendor category is structurally exempt: if compromise occurs upstream at the publishing-credential layer, downstream guarantees become circular.
The technical irony is that the explicit targeting of AI tools and MCP configurations signals awareness of the contemporary threat model. Coding assistants and model-context protocols are becoming autonomous attack surfaces: credentials embedded in these tools are no longer just "development secrets" but vectors into AI-centric infrastructure.
The package remains deprecated but not removed from the npm registry: with version pinning it is still installable. This is an architectural choice of the registry, not something an individual user can resolve. The awareness that npm 12 does not stop generation 2 — and that the operator anticipated this — must inform risk assessment in pipelines migrating to the new package-manager version.
Frequently Asked Questions
Why was version 8.18.0 omitted from Jscrambler's advisory?
The dossier provides no explanation. StepSecurity documents it with a 17:46 UTC timestamp; Jscrambler lists 8.14.0, 8.16.0, 8.17.0, and 8.20.0. The reason for the omission is unknown.
Does payload execution require root privileges?
No: macOS persistence uses ~/Library/LaunchAgents (user space), and the dropper writes to temporary directories. Linux eBPF typically requires CAP_BPF or equivalent privileges, but the dossier does not specify whether the payload implements privilege-escalation techniques.
Is the malware source code available for analysis?
No. Analysis is conducted on native binaries. StepSecurity notes that analysis of the embedded eBPF program is still ongoing; the exact content of the kernel hooks is not yet known.
Sources
- https://www.bleepingcomputer.com/news/security/hackers-backdoor-jscrambler-npm-package-with-infostealer-malware/
- https://thehackernews.com/2026/07/compromised-jscrambler-8140-npm-release.html
- https://securityboulevard.com/2026/07/jscrambler-npm-package-compromised-a-security-vendor-becomes-the-supply-chain-risk/
- https://defend.network/briefings/npm-supply-chain-zimbra-rce-android-malware-2026-07-13.html
- https://www.stepsecurity.io/blog/jscrambler-npm-package-publishes-malicious-preinstall-binary
- https://krebsonsecurity.com/2026/07/fbi-seizes-netnut-proxy-platform-popa-botnet/
- https://www.bleepingcomputer.com/
- https://www.bleepingcomputer.com/tutorials/