ChainDrop supply chain compromise: Anatomy of a self-propagating worm
Microsoft Threat Intelligence identified a large-scale npm supply chain attack affecting 400+ packages across multiple publishers, delivering a self-propagating credential-stealing worm called Mini Shai-Hulud. The malware executes via npm preinstall lifecycle hooks, harvests credentials from developer workstations and CI/CD environments, authenticates to cloud and infrastructure services to enumerate additional secrets, and uses stolen npm publishing tokens to automatically modify and republish packages — creating worm-like propagation. Persistence is achieved by injecting malicious configuration files into Claude and VS Code workspace settings within compromised GitHub repositories.
- domainjs-mirror[.]comEarlier C2 domain candidate used by the worm before rotating to npm-cache.com
- domainnpm-cache[.]comActive C2 domain returned by the on-chain smart contract at time of analysis; used for HTTPS exfiltration of encrypted stolen credentials
- domainpypi-get[.]comEarlier C2 domain candidate used by the worm before rotating to npm-cache.com
- sha25654dc7ea54a1317cca0e890a2770630cf7fa6c97813e0cb9d2caa93012b350668setup.mjs npm tarball preinstall loader — the initial malicious file executed via npm preinstall lifecycle hook to launch the Bun-based payload
- sha2569fc2570b7cef51c1b8df116d144d11ff4096357be7d2c4c6367cfc2509cf1bccMath_*.js — the large obfuscated Bun-based JavaScript bundle (~710 KB) containing the worm's credential theft and propagation logic
- sha256fd3ca4007b225fdf8de7af4345a19179d5efa8c4bb9205f88cda806e5684b1ebsetup.mjs variant used as repository loader injected into .claude and .vscode configuration directories for persistence
- urlhxxps://npm-cache[.]com:443/routerPrimary HTTPS C2 endpoint for exfiltrating encrypted credential data from compromised developer workstations and CI/CD systems
Detection / Hunteropenrouter
What Happened
Attackers compromised over 400 npm packages (software libraries used by developers) by stealing publisher credentials and injecting malicious code into them. When a developer or automated build system installed one of these packages, the malicious code ran automatically before installation finished, stealing stored passwords and access keys for services like GitHub, Amazon Web Services, Kubernetes, and HashiCorp Vault. The malware then used those stolen credentials to publish more infected packages, spreading itself like a worm across the software ecosystem. It also planted hidden files in developer tool configurations (Claude and Visual Studio Code) so the infection could restart even after the original package was removed. Organizations that installed any affected package should rotate all exposed credentials, rebuild affected systems from trusted sources, and check for signs of compromise. Updating to npm CLI v12 and enabling its min-release-age feature can help prevent installing freshly published malicious packages.
Key Takeaways
- Over 400 npm packages across unrelated publishers were compromised with a self-propagating credential-stealing worm called Mini Shai-Hulud, delivered via npm preinstall lifecycle hooks.
- The malware steals npm, GitHub, AWS, Kubernetes, and HashiCorp Vault credentials, then uses them to enumerate and exfiltrate secrets via authenticated API calls.
- Worm propagation: stolen npm publishing tokens are used to download package tarballs, inject the malware, increment patch versions, and republish — creating rapid lateral spread across the npm ecosystem.
- Persistence is established by injecting malicious setup files into Claude (.claude/settings.json, .claude/setup.mjs) and VS Code (.vscode/tasks.json, .vscode/setup.mjs) configuration paths in compromised repositories.
- C2 domain resolution uses an on-chain Ethereum smart contract (0xE1f2395ee43e45A1556EC6438a88c31B83493103) with a GitHub commit fallback (marker: thebeautifulmarchoftime), making infrastructure takedown difficult.
Affected Systems
- Developer workstations with npm and Node.js installed
- CI/CD build runners and GitHub Actions environments
- npm packages including keyv, flat-cache, cache-manager, and 400+ others
- Cloud environments with AWS, Kubernetes, and HashiCorp Vault integrations
- GitHub repositories with Claude or VS Code workspace configurations
Vulnerabilities (CVEs)
None identified.
Attack Chain
- Initial Access: Stolen npm maintainer credentials or GitHub Actions OIDC publishing tokens used to publish malicious package versions directly to npm registry
- Execution: npm preinstall lifecycle hook automatically runs setup.mjs before package installation completes, launching the obfuscated Bun-based JavaScript payload
- Credential Discovery: Malware collects credentials from local files, environment variables, shell histories, SSH keys, cloud configs, and GitHub Actions runner memory
- Collection: Stolen credentials used to authenticate to npm, GitHub, AWS, Kubernetes, and HashiCorp Vault APIs to enumerate and retrieve additional secrets
- Exfiltration: Collected data encrypted with AES-256-GCM (key wrapped via RSA-OAEP-SHA256) and exfiltrated via HTTPS C2 endpoint; GitHub repositories used as fallback exfiltration channel
- Propagation: Stolen npm publishing tokens used to download package tarballs, inject malware and preinstall hook, increment patch version, and republish — creating worm-like spread across all packages accessible to compromised identity
- Persistence: Malicious setup files injected into Claude (.claude/settings.json, .claude/setup.mjs) and VS Code (.vscode/tasks.json, .vscode/setup.mjs) configuration paths in compromised GitHub repositories
Detection Availability
- YARA Rules: No
- Sigma Rules: No
- Snort/Suricata Rules: No
- KQL Queries: Yes
- Splunk SPL Queries: No
- EQL Queries: No
- Other Detection Logic: No
- Platforms: Microsoft Defender XDR Advanced Hunting (KQL), Microsoft Defender Antivirus, Microsoft Defender for Endpoint, Microsoft Defender for Cloud
The article provides multiple KQL advanced hunting queries for Microsoft Defender XDR covering preinstall script execution, Bun runtime second-stage execution, malicious file hash detection, and credential access by malicious JavaScript. Microsoft Defender Antivirus and Defender for Endpoint detection names are also listed for trojan, behavior, and suspicious activity categories.
Detection Engineering Assessment
| Dimension | Rating | Rationale |
|---|---|---|
| EDR Visibility | Medium | The article references Defender for Endpoint detections for suspicious Node.js/Bun process behavior and credential access patterns. However, the malware's use of legitimate JavaScript runtimes and npm lifecycle hooks may blend with normal developer activity on systems without specialized application-aware telemetry. |
| Network Visibility | Medium | C2 communication occurs over HTTPS to attacker-controlled domains, which could be detected via domain reputation or TLS metadata. However, the fallback exfiltration via GitHub repositories uses legitimate GitHub API traffic, making network-only detection insufficient. |
| Detection Difficulty | Hard | The malware uses legitimate developer tooling (npm, node, Bun), legitimate cloud APIs for credential enumeration, and legitimate GitHub infrastructure for fallback exfiltration. Distinguishing malicious activity from normal developer workflow requires correlation across process ancestry, file hashes, credential access patterns, and package publication anomalies. |
Required Log Sources
- DeviceProcessEvents (process creation, command line arguments)
- CloudProcessEvents (CI/CD process telemetry)
- DeviceFileEvents (file creation and hash matching)
- DNS resolution logs (for C2 domain lookups)
- GitHub audit logs (repository modifications, new file commits)
- npm publish logs (unauthorized package releases)
- Cloud provider API logs (AWS STS, Secrets Manager, Kubernetes API, Vault audit logs)
Hunting Hypotheses
| Hypothesis | Telemetry | ATT&CK Stage | FP Risk |
|---|---|---|---|
| Consider hunting for Node.js processes spawning Bun runtime processes from within node_modules directories, as this pattern indicates the preinstall loader executing the second-stage obfuscated payload. | DeviceProcessEvents — process creation with parent-child relationship between node.exe and bun.exe, folder paths containing node_modules or bun-dl- | Execution | Medium — legitimate development workflows may use both Node.js and Bun, but execution from node_modules with bun-dl- paths is suspicious |
| Consider hunting for Bun runtime processes invoking cloud CLI tools (gh, gcloud, az) to retrieve authentication tokens, as this indicates the malware's credential collection phase. | DeviceProcessEvents — process command lines containing 'gh auth token', 'gcloud config config-helper', 'az account get-access-token' with parent process of bun.exe | Credential Access | Low — legitimate use of cloud CLI tools from Bun runtime is uncommon |
| Consider hunting for file creation events matching the known malicious SHA256 hashes (setup.mjs variants and Math_*.js) across developer endpoints and CI/CD build systems. | DeviceFileEvents — file creation events matching known malicious file hashes | Execution | Low — hash-based detection is highly specific |
| Consider hunting for unexpected modifications to package.json files adding preinstall lifecycle scripts, especially when paired with version increments without corresponding source commits. | GitHub audit logs, file integrity monitoring on developer workstations, CI/CD pipeline artifact inspection | Propagation | Medium — legitimate packages do use preinstall hooks, but combined with version bumps lacking source commits it is suspicious |
| Consider hunting for DNS queries to npm-cache.com, pypi-get.com, or js-mirror.com, or for HTTPS connections to the C2 URL path /router on these domains. | DNS logs, proxy logs, firewall connection logs | Exfiltration | Low — these domains are not associated with legitimate services |
Control Gaps
- Traditional AV signatures may not detect obfuscated JavaScript payloads executed via legitimate runtimes (Node.js, Bun)
- Network security controls may not flag HTTPS exfiltration to newly registered domains or legitimate GitHub API traffic used as fallback
- CI/CD pipeline security may not detect unauthorized package publications that carry valid provenance from compromised OIDC workflows
- Endpoint DLP may not capture credential theft from environment variables and shell history files by JavaScript processes
- Package registry controls may not flag rapid patch-version increments across multiple packages from a single publisher as anomalous
Key Behavioral Indicators
- Node.js process executing setup.mjs as a child of npm installation process
- Bun runtime process spawned by Node.js with folder path containing bun-dl- or node_modules
- JavaScript process (node/bun) invoking cloud CLI tools to retrieve authentication tokens
- File creation of Math_Symbol.js, Math_init.js, or math_<guid>.js in Node.js working directories
- Unexpected preinstall script addition in package.json with 'node setup.mjs' command
- GitHub repository modifications creating files in .claude/ or .vscode/ directories with setup.mjs content
- npm package publications with patch version increments but no corresponding source code commits or pull requests
False Positive Assessment
Medium — npm preinstall scripts and Node.js/Bun process execution are common in legitimate development workflows. However, the specific combination of setup.mjs execution, Bun runtime spawning from node_modules, cloud CLI token retrieval by JavaScript processes, and known malicious file hashes provides strong discriminators. Domain-based detections for npm-cache.com, pypi-get.com, and js-mirror.com carry low false positive risk.
Recommendations
Immediate Mitigation
- Verify against your organization's incident response runbook and team escalation paths before acting. Consider identifying all developer workstations and CI/CD build runners that installed any of the 400+ affected npm packages, especially keyv, flat-cache, and cache-manager.
- Consider revoking and rotating all credentials that may have been accessible to compromised systems — including npm tokens, GitHub tokens, AWS keys, Kubernetes service account tokens, and HashiCorp Vault secrets — from a known-clean environment.
- If applicable, purge npm and yarn caches on affected developer endpoints and build hosts, including shared CI caches where compromised tarballs may have been stored.
- Consider rebuilding affected systems and downstream build artifacts from trusted, known-good dependency baselines, verifying that compromised hashes are absent from package caches and artifact stores.
- If your organization uses shared base images or golden build runners, consider rebuilding those images to prevent future jobs from inheriting poisoned caches or persistence mechanisms.
Infrastructure Hardening
- Consider updating npm CLI to version 12 and enabling the min-release-age feature to delay installation of newly published packages, reducing exposure to freshly published malicious versions.
- Evaluate whether pinning known-good package versions in lockfiles and dependency manifests would reduce risk of automatically pulling malicious patch releases.
- Consider reviewing GitHub Actions OIDC trusted publisher configurations, token scopes, workflow approvals, and protected environments to detect and prevent unauthorized package publication through compromised workflow identities.
- If supported by your tooling, consider implementing anomaly detection around automated package publication patterns — such as rapid patch-version increments across multiple packages without corresponding source commits.
- Evaluate whether network controls can block or alert on DNS queries to known C2 domains (npm-cache.com, pypi-get.com, js-mirror.com) and HTTPS connections to the /router endpoint.
User Protection
- Consider deploying endpoint detection that flags suspicious Node.js or Bun runtime process behavior, especially credential access patterns and script execution from node_modules directories.
- If your EDR supports it, consider enabling behavioral detections for JavaScript processes invoking cloud CLI authentication commands (gh, gcloud, az).
- Consider reviewing developer endpoints for lingering artifacts such as Math_Symbol.js, Math_init.js, or files matching math_<guid>.js naming patterns.
- Evaluate whether Microsoft Defender Antivirus cloud-delivered protection and Microsoft Defender for Endpoint telemetry are enabled across all developer and CI/CD assets.
Security Awareness
- Consider incorporating supply chain attack awareness into existing developer training programs, emphasizing the risk of npm lifecycle scripts executing code before package installation completes.
- If applicable, consider educating development teams on the importance of reviewing dependency changes, lockfile diffs, and unexpected package version bumps in pull requests.
- Consider reminding developers to use scoped, short-lived tokens for npm and GitHub rather than long-lived global credentials, and to avoid storing credentials in environment variables accessible to build processes.
- Where supported by your organization's policies, consider encouraging developers to review .claude/ and .vscode/ configuration files in repositories for unexpected additions.
MITRE ATT&CK Mapping
Initial Access
Execution
Persistence
Credential Access
Discovery
Command and Control
Additional IOCs
- File Paths:
setup.mjs- Malicious loader file placed inside npm package tarballs and injected into .claude/ and .vscode/ directories for persistenceMath_Symbol.js- Malicious JavaScript payload artifact produced by the worm on compromised endpoints; should be hunted for in endpoint telemetryMath_init.js- Malicious JavaScript payload artifact produced by the worm on compromised endpoints; should be hunted for in endpoint telemetry.claude/settings.json- Claude configuration file targeted for malicious injection to establish persistence in compromised GitHub repositories.claude/setup.mjs- Malicious setup file injected into Claude configuration directory for persistence and secondary infection route.vscode/tasks.json- VS Code tasks configuration file targeted for malicious injection to establish persistence in compromised repositories.vscode/setup.mjs- Malicious setup file injected into VS Code configuration directory for persistence and secondary infection route
- Command Lines:
- Purpose: Execute the malicious preinstall loader via npm lifecycle hook | Tools:
node,npm| Stage: Execution |node setup.mjs - Purpose: Inject preinstall hook into package.json to trigger malware on installation | Tools:
npm| Stage: Propagation |preinstall: "node setup.mjs"
- Purpose: Execute the malicious preinstall loader via npm lifecycle hook | Tools:
- Other:
thebeautifulmarchoftime- Cryptographically verified signed GitHub commit marker used as fallback C2 domain resolution source when the on-chain contract is unavailableShai-Hulud: Here We Go Again- GitHub repository description used by the malware when creating a public fallback exfiltration repository with stolen credentials