Cross-linked persistence | Image: Unit 42
At a glance
| Malware family | ChainDrop (Shai-Hulud code lineage) |
| Threat actor | Unattributed; possible link to TeamPCP (not confirmed) |
| Targets | Developer workstations, CI pipelines, cloud environments |
| Delivery vector | Infected npm packages via preinstall lifecycle hook |
| Key capabilities | Credential theft, CI memory scraping, self-propagation, Ethereum-based C2, remote code execution channel |
| Source | Unit 42, Palo Alto Networks |
TL;DR
A self-propagating npm worm called ChainDrop has infected more than 400 packages downloaded hundreds of millions of times each week. It steals cloud credentials, CI secrets, and SSH keys, then spreads by republishing infected packages. C2 addresses resolve through an Ethereum smart contract, letting the operator rotate infrastructure with a single blockchain transaction.
Delivery
On August 4, 2026, Unit 42 researchers spotted ChainDrop active across 10 distinct environments. The worm enters via a poisoned npm package. Widely used libraries such as keyv and cacheable-request carried malicious versions.
The modification is minimal by design. The attacker adds one line to the package.json file: a preinstall hook pointing to a dropper named setup.mjs. That single change is the only visible difference from a clean package. No errors appear during install. No warnings fire.
Unit 42 notes the delivery is quiet: “Most developers would move on without noticing a key detail: The worm is already running.”
Infection chain
The dropper first checks whether the Bun JavaScript runtime is present. If not, it downloads Bun from the legitimate Oven GitHub repository. Then it feeds Bun a 727 KB obfuscated payload compressed into just two source lines.
The payload spawns a background process and lets the install finish cleanly. In CI environments it runs inline instead, leaving traces in workflow logs – a useful signal for defenders. Furthermore, the worm skips machines set to a Russian-language locale, printing an exit message and stopping all activity.
Persistence through developer tools
Two persistence paths deserve special attention. First, the worm writes a VS Code task file that runs the dropper whenever a developer opens the project folder. Second, it writes a Claude Code settings file that fires the dropper at every session start.
Each config file points at a dropper copy in the other tool’s directory. Cross-referencing makes each artifact look like it belongs to the other tool. Additionally, the worm carries a macOS LaunchAgent and Linux systemd installer – but Unit 42 found no call site for that installer in this sample. Treat OS-level persistence as latent capability, not confirmed behavior.
Command and control and data theft
Blockchain-based C2 routing
ChainDrop does not hardcode a C2 domain. Instead, it queries an Ethereum smart contract to retrieve the active server address. This design means the operator can rotate the entire C2 infrastructure with one on-chain transaction – no malware update needed.
On August 4, Unit 42 observed exactly that: the operator executed a single Ethereum transaction that swapped the active domain. The new domain became operational within the hour and Unit 42 confirmed victim traffic to it across four continents within 19 hours.
If contract resolution fails, the worm falls back to a GitHub commit search using a fixed marker string. That fallback was unarmed at analysis time, but the mechanism is fully built and waiting.
What ChainDrop steals
Once running, the worm sweeps the machine for credentials. Targets include cloud IAM tokens from major platforms, npm and GitHub tokens, SSH keys, Docker and Helm configs, Terraform state, Vault tokens, and wallet files. It also collects AI coding tool configurations.
Beyond files, ChainDrop scrapes live GitHub Actions runner memory. An embedded Python helper locates the Runner.Worker process and reads process memory directly, capturing OIDC tokens and runner secrets before they vanish when a job ends.
Stolen data is JSON-serialized, gzipped, AES-256-GCM encrypted with a random key, and wrapped with an embedded RSA public key before transmission. Network captures can confirm that data left the machine, but decryption requires the operator’s private key.
Self-propagation
The worm uses stolen npm tokens to republish infected versions of every package the compromised account can publish. It preserves the original source code, adds the two dropper files and the lifecycle hook, increments the patch version, and publishes. The package still works normally.
Unit 42 also found a quieter second path targeting the opensearch-js repository. This path requests a legitimate npm OIDC publish token directly from the GitHub Actions runner, signs the package with valid Sigstore provenance, and publishes without a stolen token. As Unit 42 warns, “a package having valid npm provenance does not mean the package is clean.”
Attribution
Attribution is suspected, not confirmed. ChainDrop shares code patterns with the Shai-Hulud toolchain documented by JFrog, including its string decoder, runtime pin, and self-propagation design. However, because the Shai-Hulud source became public in May 2026, any actor could reuse it. Unit 42 states clearly it “cannot yet say whether it’s operated by the group known as TeamPCP, or by another group adapting the published toolkit.”
Detection and defense
Unit 42 detected ChainDrop across 10 environments using XDR detections focused on JavaScript runtime events. For defenders, several concrete steps apply immediately.
First, audit all npm package.json files for unexpected preinstall hooks. Second, search for the five dropped files: .claude/math_init.js, .claude/settings.json, .claude/setup.mjs, .vscode/setup.mjs, and .vscode/tasks.json. Third, scan public GitHub commits for the marker string “IfYouBlockThisAPIKeyItWillCrashTheLiveProductionServersOfAllThirdPartyClients” – a match means a live credential needs revoking now.
Next, revoke and rotate all npm, GitHub, cloud, and SSH credentials on any system that installed an affected package. Also clear lockfiles, caches, and CI images – rolling back to a clean package tag does not remove poisoned lockfiles already in the pipeline.
Finally, block the C2 domain at the domain or SNI level rather than by IP, and monitor the Ethereum smart contract for new domain writes.
Support Our Threat Intelligence
If you find our CVE report and cybersecurity news helpful, consider supporting our work.