jscrambler npm Package Compromised in Supply Chain Attack
A compromised release of the jscrambler npm package (versions 8.14.0 through 8.20.0) delivered a Rust-built cross-platform infostealer via hidden native binaries embedded in an obfuscated CSI container. The malware executes automatically during npm install via a preinstall hook or, in later versions, through injected self-executing functions in package entry points, evading --ignore-scripts protections. The infostealer broadly harvests developer credentials including cryptocurrency wallets, AI assistant API keys, cloud provider credentials, browser data, and messaging app tokens, exfiltrating them over TLS via rustls.
- sha256a41a523ef9517aab37ed6eea0ec881821bdcb7aefcb5c5f603adc7907f868c86SHA-256 hash of dist/intro.js, the obfuscated binary container packing three gzip-compressed native executables (Linux ELF, Windows PE, macOS Mach-O)
- sha256a742de963f14a92d24ebcbc7b44ac867e23a20d31d1b0094a13a4f83287f4e60SHA-256 hash of dist/setup.js, the malicious loader script that reads the CSI container and spawns platform-specific binary
- sha256b7ca95d1b23c8e67416a25cedf741de0917c2096bbc9d24649eea7853d054903SHA-256 hash of the decompressed Windows x86-64 PE32+ infostealer payload
- sha256bba32ddeab075a5e5015eec50f5d2af364c95b848732c714aea6b6baf78f49f0SHA-256 hash of the malicious package.json containing the undocumented preinstall hook
- sha256c8fd47d36bdf7c825378593ab82ed8c24d1dc52e26b507812393e24e1d5201fdSHA-256 hash of the decompressed macOS arm64 Mach-O infostealer payload
- sha256fbbcf4d8f98168f78f5c0c47a9ae56d59ec8ac84a7c9ca6b797fedfb8d62d2bdSHA-256 hash of the decompressed Linux x86-64 ELF infostealer payload
Detection / Hunteropenrouter
What Happened
A popular npm package called jscrambler, used by developers to protect JavaScript code, was compromised by an attacker who published malicious versions. When developers installed these versions, hidden malicious programs automatically ran on their computers — they didn't even need to use the package, just installing it was enough. The malicious software was designed to steal sensitive information like cryptocurrency wallets, cloud service passwords, AI coding assistant credentials, and browser data from developer machines. Later versions of the attack were modified to evade security scanners that only check for install-time scripts. Anyone who installed the affected versions should remove them, check their systems for compromise, and change any passwords or credentials that might have been exposed. The package maintainers have since fixed the issue and version 8.22.0 is safe to use.
Key Takeaways
- Compromised jscrambler npm package versions 8.14.0, 8.16.0, 8.17.0, 8.18.0, and 8.20.0 delivered a Rust-built cross-platform infostealer via hidden native binaries
- Initial versions used a preinstall hook to execute code during npm install; later versions (8.18.0+) injected the dropper into dist/index.js and dist/bin/jscrambler.js to evade --ignore-scripts and script-only scanners
- The infostealer broadly targets developer credentials: crypto wallets, AI assistant configs (Claude, Cursor, Windsurf), cloud credentials (AWS/GCP/Azure), browser data, and messaging apps (Discord, Slack, Telegram)
- Malware uses per-string ChaCha20-Poly1305 encryption for ~2,400 configuration strings, with payloads embedded in a custom CSI container format (header: 1b 43 53 49 01)
- Version 8.22.0 is confirmed clean; users should upgrade or pin to 8.13.0 and rotate any credentials accessible to affected environments
Affected Systems
- Developer workstations (Linux x86-64, Windows x86-64, macOS arm64)
- CI/CD build systems and automated build pipelines
- Any environment where jscrambler npm package versions 8.14.0, 8.16.0, 8.17.0, 8.18.0, or 8.20.0 were installed
Vulnerabilities (CVEs)
None identified.
Attack Chain
- Initial Access: Attacker uses compromised npm publishing credentials to publish malicious jscrambler package versions (8.14.0–8.20.0)
- Execution: preinstall hook runs dist/setup.js during npm install (8.14.0–8.17.0) or self-executing function in dist/index.js fires on import/CLI use (8.18.0+)
- Defense Evasion: setup.js reads obfuscated CSI container (dist/intro.js), selects platform-specific binary, decompresses to randomly named hidden file in temp directory
- Collection: Rust-built infostealer harvests credentials from crypto wallets, AI assistant configs, cloud metadata services, browsers, and messaging apps using ChaCha20-Poly1305-encrypted configuration strings
- Persistence: Attempts local privilege escalation via sudo and systemd-run; references systemd units, crontab, and macOS LaunchAgents for persistence
- Exfiltration: Stolen data exfiltrated via TLS (rustls) using POST /upload multipart/form-data requests to attacker-controlled drop server
Detection Availability
- YARA Rules: No
- Sigma Rules: No
- Snort/Suricata Rules: No
- KQL Queries: No
- Splunk SPL Queries: No
- EQL Queries: No
- Other Detection Logic: No
The article provides SHA-256 hashes for all malicious files and detailed technical analysis of the malware's string encryption scheme, but does not include any YARA, Sigma, Snort, Suricata, KQL, SPL, or EQL detection rules. A reproduction outline for string decryption is mentioned in an appendix.
Detection Engineering Assessment
| Dimension | Rating | Rationale |
|---|---|---|
| EDR Visibility | Medium | The dropped binary executes from a temp directory with a random name, spawned as a detached process with windowsHide enabled. EDR should capture process creation and file write events, but the detached execution and hidden window may reduce visibility on some platforms. The later versions that inject into existing package entry points (dist/index.js) may be harder to distinguish from legitimate Node.js activity. |
| Network Visibility | Medium | Exfiltration occurs over TLS via rustls with POST /upload multipart/form-data requests. While the TLS traffic itself is encrypted, network monitoring could detect outbound connections to previously unknown servers and the multipart upload pattern. The malware also queries legitimate cloud metadata endpoints and APIs which may blend with normal developer traffic. |
| Detection Difficulty | Moderate | The preinstall hook execution and temp directory binary drop are detectable through standard EDR telemetry. However, the later versions that inject into dist/index.js evade script-only scanners and --ignore-scripts protections. The ChaCha20-Poly1305 string encryption and CSI container obfuscation add complexity to static analysis. The broad credential harvesting across many applications generates diverse file access patterns that may be difficult to correlate without comprehensive file access monitoring. |
Required Log Sources
- npm install logs and package manager telemetry
- Process creation and file write events (EDR)
- Node.js process execution logs with command line arguments
- Network connection logs with TLS metadata
- File system monitoring for temp directory writes
- Cloud metadata API access logs (AWS IMDS, GCP metadata, Azure IMDS)
Hunting Hypotheses
| Hypothesis | Telemetry | ATT&CK Stage | FP Risk |
|---|---|---|---|
| Hunt for npm packages with preinstall or postinstall hooks that execute JavaScript files from the dist/ directory, especially if those files are new additions in a package version diff | npm install logs, package.json inspection, file system change monitoring | Initial Access / Execution | Medium — legitimate npm packages commonly use preinstall hooks for build steps |
| Hunt for Node.js processes spawning detached child processes with windowsHide and stdio ignore options in temp directories | EDR process telemetry with command line and parent-child process correlation | Execution | Low — this specific combination of detached, hidden, temp-resident binary execution is rare in legitimate Node.js applications |
| Hunt for files with the custom CSI container header (bytes 1b 43 53 49 01) on disk, particularly files with .js extensions | File system scanning with binary content inspection | Defense Evasion | Low — this is a custom container format not associated with legitimate software |
| Hunt for single processes accessing multiple credential stores in rapid succession, including browser cookie databases, cloud credential files, crypto wallet extension directories, and AI assistant config files | EDR file access telemetry with process-to-file access correlation | Collection | Medium — some legitimate developer tools may access subsets of these locations, but broad access across all categories is suspicious |
| Hunt for outbound TLS connections from Node.js or unknown processes to previously unseen servers with multipart/form-data POST request patterns | Network proxy logs, TLS connection metadata, IDS/IPS with HTTP inspection | Exfiltration | Medium — legitimate file upload services use similar patterns |
Control Gaps
- npm --ignore-scripts does not prevent execution of malicious code injected into package entry points (dist/index.js, dist/bin/jscrambler.js)
- Static package scanners that only inspect preinstall/postinstall hooks would miss the 8.18.0+ delivery mechanism
- Standard AV may not detect the obfuscated CSI container or the ChaCha20-Poly1305-encrypted configuration strings
- Network DLP may not flag TLS exfiltration to unknown servers if allowlisting is not enforced
- Cloud metadata endpoint access from developer workstations may not be monitored or restricted
Key Behavioral Indicators
- Node.js process spawning a detached binary with { detached: true, stdio: 'ignore', windowsHide: true } options
- Files with custom CSI container header bytes (1b 43 53 49 01) and .js extension
- Randomly named executable files appearing in system temp directory during or shortly after npm install
- preinstall hook in package.json executing 'node dist/setup.js'
- Self-executing function injected at the top of dist/index.js or dist/bin/jscrambler.js
- Process accessing both browser credential stores and cloud credential files (e.g., application_default_credentials.json, credentials.db) within a short time window
- Outbound TLS connection with POST /upload multipart/form-data request to previously unknown server
False Positive Assessment
Low — the SHA-256 hashes are specific to the malicious package files and native payloads. The CSI container header (1b 43 53 49 01) is a custom format not associated with legitimate software. The combination of detached binary execution from temp directories with windowsHide enabled is rare in legitimate Node.js applications. However, preinstall hooks themselves are common in legitimate npm packages, so that individual indicator carries medium FP risk.
Recommendations
Immediate Mitigation
- Verify against your organization's incident response runbook and team escalation paths before acting. If [email protected], 8.16.0, 8.17.0, 8.18.0, or 8.20.0 was installed in any environment, consider isolating affected machines and rotating all credentials accessible to those systems, including cloud credentials, API keys, deployment tokens, and crypto wallet seeds.
- Audit npm installation logs and package-lock.json files across developer workstations and CI/CD systems for any of the five compromised jscrambler versions.
- Consider pinning jscrambler to version 8.22.0 or reverting to 8.13.0 until further verification, and evaluate whether your dependency management process enforces version pinning.
- Review file system logs for evidence of dist/setup.js or dist/intro.js execution, and for randomly named executables in temp directories created around npm install timestamps.
Infrastructure Hardening
- Evaluate whether your CI/CD pipelines enforce dependency pinning and package integrity verification via package-lock.json with integrity hashes.
- Consider implementing automated scanning of npm packages for suspicious install hooks and unexpected file additions before they enter your build pipeline.
- If supported by your tooling, consider using --ignore-scripts for npm install in CI environments, but be aware this does not prevent execution of malicious code injected into package entry points.
- Evaluate whether cloud metadata endpoints (AWS IMDS, GCP metadata, Azure IMDS) are accessible from developer workstations and consider restricting access where feasible.
- Consider implementing egress filtering or allowlisting for outbound TLS connections from build and development environments.
User Protection
- Consider deploying EDR or endpoint monitoring that detects Node.js processes spawning detached, hidden binaries in temp directories.
- Evaluate whether developer workstations have credential stores (browser cookies, crypto wallets, cloud CLI credentials, AI assistant API keys) that could be harvested by a similar infostealer, and consider segmenting or encrypting these where possible.
- If applicable, consider using hardware security keys (HSMs) or cloud-based secret managers instead of storing credentials in local files on developer machines.
Security Awareness
- Consider adding supply chain attack scenarios to existing security awareness training, emphasizing that npm install can execute arbitrary code before any application code runs.
- If applicable, remind developers to review package release notes and file diffs before upgrading dependencies, especially for packages with high download counts.
- Consider educating development teams on the risk of credential exposure on build and development machines, and the importance of rotating credentials after suspected compromise.
MITRE ATT&CK Mapping
Initial Access
Execution
Persistence
Privilege Escalation
Stealth
Credential Access
Discovery
Collection
Exfiltration
Additional IOCs
- File Paths:
dist/setup.js- Malicious loader script added in compromised jscrambler releases; reads CSI container and spawns platform-specific binarydist/intro.js- Obfuscated binary container with custom CSI header packing three native executables; despite .js extension, is not JavaScriptdist/index.js- Existing package entry point modified in versions 8.18.0+ to include self-executing dropper function at the top of the filedist/bin/jscrambler.js- CLI entry point modified in versions 8.18.0+ to include self-executing dropper function at the top of the file
- Command Lines:
- Purpose: Execute dropped native binary in background as a detached process with no I/O | Tools:
node,child_process| Stage: Execution |spawn(<binary>, { detached: true, stdio: 'ignore', windowsHide: true }) - Purpose: Local privilege escalation by reading password from stdin | Tools:
sudo| Stage: Privilege Escalation |sudo -S -p - Purpose: Local privilege escalation without password prompt | Tools:
systemd-run| Stage: Privilege Escalation |systemd-run --system --no-ask-password
- Purpose: Execute dropped native binary in background as a detached process with no I/O | Tools:
- Other:
[email protected]- Second compromised release; identical payload to 8.14.0, delivered via preinstall hook[email protected]- Third compromised release; identical payload, delivered via preinstall hook[email protected]- Fourth compromised release; dropper injected into dist/index.js and dist/bin/jscrambler.js instead of preinstall hook to evade --ignore-scripts[email protected]- Fifth compromised release; declares self-dependency on jscrambler@^8.17.0 for transitive compromise