ChainDrop Worm Infected Over 400 npm Packages While Leaving Their Source Code Clean
A worm called ChainDrop hijacked a maintainer's GitHub account to spread through hundreds of npm packages by rewriting their published tarballs instead of source code, then hid its command server...
On August 4, 2026, an attacker compromised the GitHub account belonging to the maintainer of keyv, a widely used npm caching library, and used it to launch a self-replicating worm that Microsoft’s security research team named ChainDrop. More than a week later, security researchers are still unpacking exactly how quietly it spread: rather than tampering with the source code developers actually review, ChainDrop rewrites the compressed packages npm distributes after the fact, then locates its command server by querying an Ethereum smart contract instead of a fixed domain. Packages hit by the worm are downloaded a combined 2 billion times a month, according to a report from The Register published this weekend.
Table Of Content
A Stolen GitHub Login, Not a Stolen npm Token
Most npm supply chain attacks start with a leaked publishing token. ChainDrop started differently: the attacker took over the maintainer’s GitHub account itself. According to a technical breakdown from StepSecurity, the compromised account pushed unsigned commits directly to keyv’s main branch and used GitHub’s own release workflow to publish new versions. Because those releases moved through legitimate CI/CD pipelines using OIDC Trusted Publishing, they carried valid SLSA provenance attestations, the cryptographic record that is supposed to prove a package build can be trusted. StepSecurity’s writeup is blunt about the gap that opened up: provenance proves the build pipeline ran as configured, not that the commit behind it was actually authorized by a human.
From keyv, the worm spread automatically into related packages maintained by the same developer, including cacheable, flat-cache, and file-entry-cache. BleepingComputer reported that downstream projects tied to companies including Deliveroo, Ornikar, Picsart, Qlik, and ServiceTitan pulled in poisoned versions.
Why Reviewing the Source Code Would Not Have Caught It
ChainDrop’s defining trick is where it hides. Instead of committing malicious code to a package’s Git history, it rebuilds the tarball, the compressed archive npm actually ships to installers, after a legitimate release already exists. Microsoft’s security team described the mechanism directly: “the propagation routine downloads a package’s latest tarball, copies the current malware bundle into it, adds a loader, and replaces its lifecycle scripts,” all without ever touching the source repository a developer would audit. Comparing a published package against its GitHub source would turn up nothing, because the tampering happens entirely after that comparison point.
The initial infection runs through npm’s preinstall lifecycle hook, so it fires automatically the moment a developer or a CI pipeline runs npm install against a poisoned version, before the install even finishes. Rather than bundling its own JavaScript engine, the dropper downloads the real, legitimate Bun runtime straight from Bun’s official GitHub releases and runs its second-stage payload through that: a living-off-the-land technique that blends in with normal developer tooling instead of shipping a distinct binary for security tools to flag.
Credentials, Everywhere
Once running, the Bun-based payload goes after credentials across nearly every cloud a target might use. StepSecurity’s analysis found it querying AWS Secrets Manager and Systems Manager parameters across 16 regions, probing HashiCorp Vault and Kubernetes configuration, and reading Claude Code’s local credentials file. On GitHub Actions runners specifically, it uses a helper script to dump readable process memory and search it for secret values before CI jobs even finish. Anything it steals is compressed, encrypted with a random AES-256 key generated for that run, and that AES key is itself sealed with an embedded RSA public key, so only the attacker holding the matching private key can ever decrypt what was taken.
Hiding the Command Center Inside a Smart Contract
The most novel part of ChainDrop is how it finds its command-and-control server. Instead of hardcoding a domain defenders could simply block, the malware queries an Ethereum smart contract, a technique StepSecurity’s researchers call EtherHiding. Microsoft’s writeup names the specific contract address, 0xE1f2395ee43e45A1556EC6438a88c31B83493103, and StepSecurity documented the malware checking it across 75 different public Ethereum RPC endpoints to fetch its answer. At the time of Microsoft’s analysis, the contract was returning the domain npm-cache[.]com; earlier versions had pointed to pypi-get[.]com and js-mirror[.]com, hinting the same infrastructure could be repointed at Python’s package ecosystem next. Because the real answer lives on a public blockchain rather than inside the malware itself, the attacker can rotate to a new domain at will, and taking down any single domain does nothing to stop the worm from finding the next one.
A New Infection Path: Just Opening the Project
ChainDrop does not only spread through npm install. Using stolen GitHub credentials, it also commits malicious configuration files, specifically .claude/settings.json and .vscode/tasks.json, directly into a victim’s other repositories and branches. The Register reported that simply opening an infected branch in Visual Studio Code or Claude Code is enough to trigger a background task that starts harvesting credentials again, with no install step required. ActiveState CEO Abby Kearns, writing about the campaign, put it bluntly: developers should now be “treating repository-supplied configuration as executable content, because that is what it is now.”
What to Actually Do About It
The affected packages were pulled from npm once discovered, but the mitigations researchers are recommending go beyond removing bad versions. Passing --ignore-scripts to npm install neutralizes ChainDrop’s initial dropper, since the entire attack depends on that preinstall hook running. sxz.io has previously covered how to set up dependency cooldowns that delay adoption of freshly published package versions by a few days, a policy StepSecurity specifically recommends here because it would have kept most installs behind the worm’s initial spread window. Provenance attestations alone are not enough, since ChainDrop’s own releases passed that check; StepSecurity recommends pairing provenance with change detection on what a release actually adds, new files and new lifecycle scripts in particular. Teams that depend on keyv, cacheable, flat-cache, or file-entry-cache should also check every branch, not just main, for unexpected .claude/settings.json or .vscode/tasks.json files, and rotate any credentials that may have touched an infected machine from a separate, clean system. sxz.io’s earlier walkthrough on detecting malicious npm preinstall scripts, written the day after the initial keyv compromise was disclosed, covers the verification steps in more detail.








No Comment! Be the first one.