Back to Feed
Supply ChainAug 4, 2026

ChainDrop supply chain compromise: Anatomy of a self-propagating worm

Credential-stealing worm in 400+ npm packages self-propagates by republishing malicious updates.

Summary

A sophisticated supply chain attack, dubbed ChainDrop, has compromised over 400 npm packages, embedding a credential-stealing worm. This worm, a variant of Mini Shai-Hulud, uses a Bun-based JavaScript payload executed via npm's preinstall lifecycle hook to steal credentials from developer workstations and CI/CD environments. The malware then uses these stolen credentials to authenticate to various services like npm, GitHub, and AWS, enabling it to enumerate sensitive data and, critically, to republish compromised packages with the malware embedded, thus self-propagating across the software ecosystem.

Full text

Share Link copied to clipboard! TagsnpmSupply chain attackContent typesResearchProducts and servicesMicrosoft DefenderTopicsActionable threat insightsThreat intelligence Microsoft Threat Intelligence identified a large-scale npm supply chain attack affecting more than 400 packages across multiple unrelated publishers, including packages associated with major enterprise software ecosystems such as keyv, flat-cache, cache-manager, and others. The malicious releases contain a Mini Shai-Hulud variant, a self-propagating credential-stealing worm delivered through a large, heavily obfuscated Bun-based JavaScript payload. The malware typically executes automatically through an npm preinstall lifecycle hook before package installation completes. Once executed, the malware searches developer workstations and continuous integration and continuous delivery (CI/CD) environments for npm, GitHub, cloud, and infrastructure credentials. It uses recovered identities to authenticate to npm, GitHub, Amazon Web Services (AWS), Kubernetes, and HashiCorp Vault, enabling it to enumerate packages, repositories, workflow secrets, cloud parameters, and secret-store values. Collected data is encrypted and transmitted through an attacker-controlled HTTPS endpoint, with GitHub repositories serving as a fallback exfiltration channel. The payload’s most significant capability is automated propagation. After obtaining an npm publishing token, it enumerates packages available to the compromised identity, downloads their latest tarballs, inserts the malware and setup loader, adds a preinstall hook, increments the patch version, and republishes the modified packages. The malware can also use stolen GitHub credentials to inject Claude and Visual Studio Code configuration files into repositories, establishing persistence and creating an additional developer-to-developer infection path. In this blog, we’re sharing our analysis of this supply chain attack, along with protection, detection, amd hunting guidance. Organizations that installed an affected package with lifecycle scripts enabled should treat the associated developer workstation or build runner as potentially compromised. Investigations should prioritize credentials accessible to the affected identity, unauthorized npm releases, unexpected repository or workflow modifications, suspicious cloud and secret-store access, and artifacts produced by affected build systems. Organizations should revoke and rotate exposed credentials from a known-clean environment and rebuild affected systems and downstream artifacts from trusted sources. Attack chain overview The campaign appeared as a rapid sequence of unauthorized patch releases across more than 400 npm packages maintained by otherwise unrelated publishers. Many malicious versions had no corresponding source-code commit, pull request, tag, or legitimate release, indicating that the attackers modified and published package tarballs directly rather than compromising each public source repository. Affected releases typically added a preinstall lifecycle script that launched a malicious file, setup.mjs, contained within the package, which launched the large, obfuscated Bun JavaScript bundle included in the package. Because npm runs preinstall scripts before installation completes, the payload could execute on developer workstations and build runners before application tests or conventional security checks began. After execution, the malware performs the following actions: Determines whether it is running on a developer workstation or in a CI/CD environment. On workstations, it detaches itself to continue after installation; on CI/CD systems, it remains in the active job to access workflow secrets, runner credentials, and OpenID Connect (OIDC) publishing permissions. Both paths could support further package or repository propagation when suitable credentials are found. Collects credentials from local files, environment variables, command-line tools, and GitHub Actions runner memory. Authenticates to npm, GitHub, AWS, Kubernetes, and HashiCorp Vault to enumerate additional accessible resources and secrets. Encrypts and exfiltrates collected data through an HTTPS channel, using GitHub repositories as a fallback. Uses recovered npm publishing access to modify and republish additional packages. Uses GitHub credentials to inject files into Claude and Visual Studio Code configurations across repository branches for persistence. The payload’s package-propagation routine downloads each publisher’s latest release, inserts itself, increments the patch version, and publishes the resulting archive. This mechanism can rapidly transform one compromised npm identity into many malicious package releases. Figure 1. Attack chain. 0. Initial publisher access Evidence points towards stolen maintainer credentials as the attack vector for initial compromise. Later propagation used stolen npm publishing tokens and, in targeted workflows, GitHub Actions OIDC publishing access. 1. Payload startup and background execution The malicious npm package uses a lifecycle hook to launch its bundle. During preflight, the payload checks the environment, exits on Russian-language systems, avoids duplicate instances, and starts a detached copy in the background on developer systems. Figure 2. Platform identification and execution. In CI environments, the payload remains attached so it can access credentials available to the active build job. 2. Initial credential discovery The payload first collects information that is immediately available from the local system, shell, and GitHub Actions runner. Figure 3. Credential discovery. The shell collector attempts to obtain the GitHub CLI token and captures the values of all process environment variables. The filesystem collector searches credential files, shell histories, cloud configuration, Secure Shell (SSH) keys, and other sensitive locations. 3. Cloud and secret store enumeration The recovered code then creates dedicated collectors for cloud and infrastructure services. Figure 4. Credential enumeration. These modules do not merely scan files for token patterns; they use available credentials to call service APIs, verify access, and retrieve additional secrets permitted to those identities. The following snippet shows the authentication attempt made using the found credentials: Figure 5. Credential validation. 4. GitHub credential theft and enumeration Discovered GitHub tokens are validated before being used for additional collection or repository access. Figure 6. GitHub credential collector. The payload checks token scopes, enumerates writable repositories, and identifies repositories where workflow execution could expose additional secrets. 6. GitHub Actions OIDC abuse The payload also contains a targeted publishing path for GitHub Actions workflows configured as npm trusted publishers. Figure 7. Re-publishing package using GitHub OIDC token. Packages published through this route can carry valid provenance because the publication originates from a legitimate workflow identity. 7. Exfiltration and fallback Collected results are serialized as JSON, gzip-compressed, and encrypted with a randomly generated AES-256-GCM using a randomly generated 32-byte key and 12-byte initialization vector (IV). The AES key is then encrypted with the attacker’s RSA public key using RSA-OAEP-SHA256. The payload first attempts delivery through an attacker-controlled dynamic HTTPS endpoint. The active domain can change through on-chain contract (0xE1f2395ee43e45A1556EC6438a88c31B83493103, selector 0x53ed5143) or, as a fallback, from a cryptographically verified signed GitHub commit (Signed fallback marker: thebeautifulmarchoftime). If that channel is unavailable, it creates a public GitHub repository with the description Shai-Hulud: Here We Go Again. Encrypted results are committed as files such as: results-<timestamp>-<counter>.json. At the time of analysis, the live contract returns npm-cache[.]c

Indicators of Compromise

  • malware — Mini Shai-Hulud

Entities

npm (product)keyv (product)flat-cache (product)cache-manager (product)Bun (product)GitHub Actions (product)