ChainDrop: how the self-propagating npm worm steals tokens and republishes itself

A Shai-Hulud-family worm turns one stolen npm token into poisoned releases of every package that publisher controls. What the advisories say, and what rotation and allowlisting limit.

Prakhar

Backend engineer · Pressentify

Published • Updated 6 November 2026

6 min read 1,320 words
Cover image titled The npm worm that republishes itself, with the subtitle ChainDrop: a stolen token becomes the next poisoned release.

Singapore’s Cyber Security Agency (CSA) published advisory AD-2026-009 on 6 Aug 2026 about an active npm supply chain attack. Malicious versions of Keyv and related packages carry malware from the Shai-Hulud family, and CSA calls the campaign “ChainDrop”: a self-propagating variant.

It matters because the dangerous part is not the first poisoned package. It is that the payload steals the credentials of whoever installs it, then uses them to publish the next poisoned versions. Your build machine can become a distribution point.

The short version: steal, publish, repeat.

What is confirmed, and by whom

Two primary sources carry this story. CSA’s advisory is the government notice. Microsoft Security Research (Ravikant Tiwari, Sagar Patil, Suriyaraj Natarajan) published a reverse-engineering analysis dated 4 Aug 2026 by its URL. Microsoft calls the payload a “Mini Shai-Hulud” variant: a self-spreading credential stealer shipped as a large, obfuscated Bun-based JavaScript bundle.

The two sources count scale in different units, so do not add them together. CSA reports more than 1,300 npm package versions compromised, with the affected packages totalling 2 billion monthly downloads. Microsoft reports more than 400 packages from multiple unrelated publishers, including keyv, flat-cache and cache-manager. CSA does not say how it counted, and its page shows a later update date than its publication date, so treat the figures as “as reported by CSA”.

What the download figure is not

The 2 billion figure is the combined monthly downloads of the affected packages. It is not a count of installs of the malicious versions, and neither source gives a victim or damage count beyond CSA’s “several organisations”.

The mechanism, step by step

  1. Run on install. Microsoft found that the malicious versions use a preinstall lifecycle hook that runs a bundled setup.mjs, which launches the Bun bundle before installation finishes.
  2. Collect secrets. The payload gathers credentials from files, environment variables, shell histories, SSH keys, cloud config, CLI tools and GitHub Actions runner memory.
  3. Test what they reach. It checks access to npm, GitHub, AWS, Kubernetes and HashiCorp Vault, and pulls further secrets those identities can read.
  4. Republish. With an npm token it lists the packages the identity can write to, checks for write permission and the ability to bypass 2FA, downloads each package’s latest tarball, inserts the malware and a loader, replaces lifecycle scripts with the preinstall hook, raises the patch version and publishes.
  5. Send the loot out. The data is JSON, gzip-compressed, encrypted with AES-256-GCM, with the key wrapped using RSA-OAEP-SHA256.
Five steps in a loop: install a poisoned version, steal credentials, list writable packages, republish a patch version, repeat on the next victim.
Our own diagram of the loop Microsoft describes: install, steal, check reach, republish, and the next install starts again.

Step four is the whole story. By Microsoft’s account, one stolen npm token can yield malicious patch releases across every package that publisher controls. The worm’s reach equals the token’s reach, which is why the scope of a token matters more than how many packages you personally maintain.

A second route that looks legitimate

Where the worm steals GitHub Actions OIDC publishing access, Microsoft says it publishes from a legitimate workflow identity, so those releases can carry valid provenance. Provenance tells you where a release was built, not that it is safe. Many other malicious versions had no matching source commit, pull request, tag or release; Microsoft concludes the attackers edited and published tarballs directly.

Two columns: a maintainer token that fans out to every package it can publish, and a narrowly scoped token that reaches one.
We drew how far one stolen token reaches: every package the identity can write to, plus the cloud and repository secrets around it.

Worked example: one maintainer, one token

This is our own illustration, not an incident from the sources. Imagine a maintainer who publishes two small libraries and runs npm install on a laptop that holds a publish token. A poisoned dependency runs its hook, finds the token, and sees both libraries are writable. It republishes each with the patch number raised by one. Everyone who updates automatically now installs the worm, and each of them is the next maintainer in this story.

It also tries to stay on developer machines

Microsoft reports that the payload injects files into repository branches: .claude/settings.json, .claude/setup.mjs, .vscode/tasks.json and .vscode/setup.mjs. The aim is that later Claude or VS Code activity restarts the payload. Treat unexpected changes to editor and agent configuration files in review as seriously as changes to source. Related reading on how agent configuration becomes an attack surface: coding agents that disabled their own safety monitors.

Who did it: not established

On initial access, Microsoft says “Evidence points towards stolen maintainer credentials.” That is a hedged statement from a vendor, not a proven finding, and Microsoft names no threat actor. We do not name one either. Whether this is part of a confirmed lineage of earlier campaigns is also not verifiable from these two sources.

Fact versus vendor claim

The behaviour of the malware (hooks, targets, republishing steps) is Microsoft’s reverse-engineering. The scale is CSA’s and Microsoft’s own counts. The guess about stolen maintainer credentials is Microsoft’s inference.

What each control is recommended to limit

Neither source says any single measure stops the worm outright, and we do not either. Here is who recommends what.

  • CSA: remove affected versions from development, build and CI/CD; treat affected systems as potentially compromised and rebuild them; rotate cloud credentials, GitHub tokens, SSH keys, Kubernetes configs, Terraform credentials and other secrets; review for unauthorised access; monitor indicators of compromise; and strengthen defences with dependency allowlisting, package integrity verification and provenance controls where available.
  • Microsoft: upgrade to npm CLI v12 and use min-release-age; check lockfiles, artifact repositories and CI caches, including transitive dependencies; pin known-good versions; purge npm and yarn caches; rotate credentials from a clean host; review token scopes, workflow approvals, protected environments and provenance; rebuild shared base images and golden runners.

Allowlisting is CSA’s recommendation only; Microsoft does not mention it and leans on pinning and release-age delay instead. The logic of each: rotation shrinks what a stolen token can still do, and an allowlist limits which versions can reach your build in the first place. Rotation done from a machine that is still infected hands the new secrets straight to the worm, which is why Microsoft says to rotate from a clean host.

Two columns comparing three controls each: CSA lists credential rotation, dependency allowlisting and rebuilding affected systems; Microsoft lists rotation from a clean host, pinning versions and min-release-age.
Our own comparison of the controls CSA and Microsoft each recommend, and which part of the loop each is meant to limit.

Similar patterns appear in other cases we have covered: a credential-stealing release of a popular LLM library, a hostage token in an npm worm incident, and a breach where one API key set the blast radius. The common thread is that a credential’s reach decides the damage.

What to do now

  1. Check lockfiles, artifact repositories and CI caches, including transitive dependencies, against CSA’s notable list (keyv 6.0.0, flat-cache 6.1.24, file-entry-cache 11.1.6, cacheable-request 13.0.20, cacheable 2.5.1, cache-manager 7.2.10, ecto 5.0.1) and the full list CSA points to at Socket.dev.
  2. If you find one, treat that machine or runner as compromised, rebuild it, and rotate secrets from a clean host.
  3. Narrow npm token scopes and review workflow approvals and protected environments so one token cannot write to everything.
  4. Pin versions, delay brand-new releases with min-release-age, and consider an allowlist for dependencies in build pipelines.
  5. Review recent branches for the four injected .claude and .vscode files listed above.

Indicators such as the exfiltration domain and Ethereum RPC endpoints are in CSA’s advisory; we do not reproduce them in full. If you must reference the domain, write it defanged, as CSA does: npm-cache[.]com.

Sources & Credits

Facts are from CSA advisory AD-2026-009 and Microsoft’s analysis; the diagrams, the one-maintainer illustration and the comparison of controls are our own work. Last verified 2026-11-05.

Share this article

Written by

Prakhar

Backend engineer · Pressentify

Backend engineer building Pressentify — interactive cheatsheets, handbooks and a job-hunt workspace.

Get the next one in your inbox

One practical backend article at a time. No spam; unsubscribe in one click.

Occasional. One-click unsubscribe.