Safeguard
Supply Chain Security•

ChainDrop npm worm shipped with valid provenance. What that proves

On 4 August 2026 the ChainDrop worm published keyv 6.0.0 and dozens of other packages through a real release workflow. The provenance was genuine, and the package was still malicious.

Safeguard Security Team
6 min read

On 4 August 2026 a worm nicknamed ChainDrop began publishing malicious versions of widely used npm packages, starting with keyv 6.0.0 and the cacheable family. Datadog Security Labs reconstructed the timeline minute by minute. The Cloud Security Alliance reports that the attacker took over the GitHub account of the keyv maintainer.

Counts differ by researcher. Per the CSA note, Endor Labs verified 1,136 malicious versions across 384 packages as a floor, and Aikido counted at least 444 packages with more than two billion monthly installs. This post is not another blast radius count. It is about one detail that surprised many teams: the keyv release had real SLSA provenance.

What's affected

Datadog named these malicious versions explicitly:

PackageVersion
keyv6.0.0
cacheable2.5.1
@cacheable/net2.1.1
@cacheable/node-cache3.1.2
@cacheable/memory2.2.1
@cacheable/utils2.5.1
flat-cache6.1.24
cacheable-request13.0.20
file-entry-cache11.1.6
cache-manager7.2.10
ecto5.0.1

Datadog says hundreds more were hit and keeps a dynamic list. The CSA advice is to pin to versions published before 4 August 2026.

What the provenance showed

On 4 August at about 09:29 to 09:35 UTC, a genuine SLSA attestation for keyv@6.0.0 entered the Rekor transparency log. It bound the tag and commit to .github/workflows/release.yaml and a specific Actions run. The malicious package published at 09:35:00 UTC.

Datadog's reading: valid provenance can faithfully bind malicious source and an attacker-controlled build. It was neither forged nor a safety verdict. The commit that added the payload to the repository was unsigned, and the main branch got a 27-file change with no recorded pull request merge. The release workflow then did exactly what it was built to do.

Datadog also notes a GitHub release event was not a reliable marker of publication. The npm artifact was live almost two hours before the keyv v6.0.0 GitHub release was published, and the tag was deleted and recreated several times.

Timeline from Datadog (UTC, 4 August)

  • 09:02: earliest recovered malicious commit, unsigned, adds the loader, a malicious preinstall and release configuration.
  • 09:14 to 09:18: an unsigned commit replays the 27-file package delta onto main with no recorded pull request merge.
  • 09:35: keyv@6.0.0 publishes with genuine provenance.
  • 10:09 to 10:14: nine malicious Cacheable-family versions publish from a second repository.
  • 10:28: ecto@5.0.1 publishes from a third.

Three different accounts committed the payload to three repositories within about 90 minutes. Datadog does not say how those credentials were obtained. The Cloud Security Alliance note reports a takeover of the keyv maintainer's GitHub account.

How it ran and spread

The package's preinstall script ran node setup.mjs, which downloaded Bun v1.3.13 from official release assets and started a second stage. The stealer collected files, environment variables, gh auth token output, AWS, Kubernetes and Vault secrets, and on Linux GitHub Actions runners it read Runner.Worker memory with sudo.

For command and control it read an Ethereum smart contract through 73 RPC endpoints to get domains, with a GitHub commit search marker and a public repository fallback. To propagate, it used stolen granular npm tokens that had bypass_2fa set, replaced a package's scripts with a preinstall entry, bumped the patch version and published. It also wrote .vscode/tasks.json and .claude/ files to up to 50 branches, to run again when a folder opens or an AI session starts.

How to check if you're exposed

npm ls keyv cacheable flat-cache file-entry-cache cacheable-request cache-manager ecto
grep -rn -E 'keyv|cacheable|flat-cache|file-entry-cache' package-lock.json | head -40
ls -la .vscode/tasks.json .claude/ 2>/dev/null
ls "${TMPDIR:-/tmp}"/tmp.dpkg_14527.lock 2>/dev/null

Datadog lists the lock file tmp.dpkg_14527.lock, the environment variable _NODE_RUNTIME_INIT=1, and the C2 domains pypi-get.com, js-mirror.com, npm-cache.com and awqhnjewqjkl.icu. Search DNS and proxy logs for them.

What to do now

  1. Pin the packages above to versions from before 4 August and rebuild from a clean checkout.
  2. Check every developer machine and CI runner that installed a listed version. Treat them as compromised.
  3. Inspect .vscode/tasks.json and .claude/ in repositories those machines touched, and remove injected hooks before rotating credentials.
  4. Rotate npm tokens (especially granular ones with bypass_2fa), GitHub tokens, cloud keys, Kubernetes and Vault credentials.
  5. Look for public GitHub repositories created under your accounts with the description "Shai-Hulud: Here We Go Again".

How this could have been avoided

  • Require review on the release path. The payload landed on main without a recorded pull request. A branch ruleset requiring a review would have put a human in front of a 27-file change.
  • Require signed commits and protect tags. The key commits were unsigned, and the release tag moved repeatedly.
  • Gate publishing on an environment with manual approval, so a push to main alone cannot ship to npm.
  • Do not issue tokens that bypass 2FA for packages with large downstream use. The worm spread with exactly that kind of token.
  • Make consumers wait. A cooldown on newly published versions, and --ignore-scripts by default in CI, would have kept the preinstall from running on most machines.

Why it matters

Provenance answers one question: was this artifact built from this commit by this workflow? ChainDrop answered yes, truthfully, for a malicious commit. Teams that treated an attestation as a green light were exposed.

Use provenance to confirm that a release came from the pipeline you expected. Use review, signing and time delays to decide whether the change itself should have been released.

Try it yourself

Pick a dependency your service relies on and look at its attestation. Write down what it proves (repository, commit, workflow) and what it cannot (intent). Then check whether you would have noticed a 27-file change with no pull request.

Click through it at your own pace, or open it full screen.

Quick check

Was the provenance on keyv 6.0.0 forged?

No. Datadog says it was genuine, binding the tag, commit and release workflow. It simply described a malicious build.

Which token feature let the worm republish other packages?

Granular npm tokens with bypass_2fa set and package write permission.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.