"Many malicious versions had no corresponding source-code commit, pull request, tag, or legitimate release. The attackers modified and published package tarballs directly rather than compromising each public source repository." - Microsoft Security Research, on ChainDrop
I ran npm audit on a small Next.js project on Thursday night, the kind of side project I keep meaning to delete, and the output listed 14 packages I had never installed by name. They were transitive. They came in through one maintainer, and the maintainer had inherited them from another. The audit said the tree was clean. I had no idea if it was right.
That is the useful place to start this post, because Microsoft's writeup of ChainDrop on 4 August was not really about a worm in npm. It was about a worm that is very good at not looking like a worm in npm. The malicious versions were not pushed from a compromised source repository. There was no source-code commit, no pull request, no tag, no legitimate release note. The attackers used stolen npm publishing tokens to download the latest tarball, insert a preinstall script, bump the patch version, and publish the modified archive. The maintainer's repo on GitHub still looked completely normal.
If you are an IT-pro at an SMB or an MSP that supports developers, your read of this should be uncomfortable. The detection signal you would have used a year ago (check the source repository, look at the commit author) does not work. Self-propagation changes the maths. The response in days is too slow. The defence has to be segmentation, lifecycle-script controls, and a credential audit before the worm does the spreading for the attackers.
TL;DR
ChainDrop is a self-propagating credential-stealing worm Microsoft published the anatomy of on 4 August 2026. It hit more than 400 npm packages, across otherwise unrelated publishers, by abusing stolen publishing tokens and the npm preinstall lifecycle hook.
- Disable or restrict lifecycle scripts in your dev environments this week.
npm ci --ignore-scriptsand the equivalent in pnpm and yarn are the single biggest fix. The preinstall hook is the worm's entry point. - Treat every developer workstation and build runner that ran
npm installagainst an affected package as compromised. Revoke and rotate the credentials that account could reach. Microsoft published the detection and hunting queries in the same advisory. - Audit your GitHub Actions workflows for npm trusted publishing and OIDC trust. ChainDrop abuses the OIDC token a workflow uses to publish to npm, which gives the malicious release a valid provenance.
- Look for unverified commits on
.claude/settings.json,.claude/setup.mjs,.vscode/tasks.json, and.vscode/setup.mjsin your repositories. The worm uses stolen GitHub tokens to inject these files as a secondary infection path. - For SMBs without a SOC, the most useful Microsoft Defender XDR detection is the published
Shai-Hulud-named KQL in the same advisory. Run it as a one-off audit against the last 30 days of sign-in and process telemetry.
What you need to do: turn off preinstall scripts in your developer environments, audit the last 30 days of npm publishes you own, rotate every credential the affected workstations and build runners could reach, and add .claude/settings.json and .vscode/tasks.json to your repo-monitoring rules.
By The Numbers: ChainDrop at a glance
| Metric | Detail |
|---|---|
| Compromised npm packages in this campaign | 400+ across unrelated publishers, including keyv, flat-cache, cache-manager |
| Worm family | Mini Shai-Hulud variant (self-propagating credential-stealing worm) |
| Payload | Bun-based JavaScript bundle, heavily obfuscated, launched from a preinstall lifecycle script |
| Where it runs first | Developer workstation or CI/CD runner, before any application test runs |
| Credentials it targets | npm publish tokens, GitHub tokens, AWS access keys, Kubernetes service accounts, HashiCorp Vault tokens |
| Self-propagation path | Uses stolen npm tokens to republish modified tarballs with a bumped patch version |
| Secondary infection path | Injects payload into .claude/settings.json, .claude/setup.mjs, .vscode/tasks.json, .vscode/setup.mjs via stolen GitHub tokens |
| Exfiltration | AES-256-GCM payload encryption, RSA-OAEP-SHA256 wrapped key, attacker-controlled HTTPS endpoint with on-chain domain selector |
| Provenance evasion | Abuses GitHub Actions OIDC tokens for npm trusted publishing, so the release has a valid provenance attestation |
| Platforms where payload self-terminates | Russian-language systems (per Microsoft's payload analysis) |
| Source | Microsoft Security Blog - ChainDrop supply chain compromise (4 Aug 2026) |
What ChainDrop actually is, and why SMB IT teams should care
The supply chain ChainDrop travels through is the same one almost every modern web project uses, including projects at companies that do not think of themselves as "software companies". The Next.js project I mentioned at the top, the small dashboard your operations team built last quarter, the internal tool your finance team runs on a server, the prototype your MSP is hosting for a client: all of them run npm install somewhere in the lifecycle. That install is now the attack surface.
The worm has four properties that make it different from the supply chain incidents most IT teams have drilled for.
1. The source repository stays clean. The attackers modify and publish the tarball directly using a stolen npm token. The maintainer's GitHub repo is untouched. There is no commit, no PR, no diff for your code review tooling to flag. The malicious version shows up as a normal patch release on npm.
2. The preinstall hook runs before any test. npm install runs the preinstall script of every dependency before the package contents are inspected. By the time the application tests run, the payload has already executed on the developer workstation. The preinstall hook is the same surface that legitimate packages use to compile native modules, so it is on by default and rarely questioned.
3. The propagation is automatic. Once the worm has an npm publishing token, it enumerates every package the compromised identity can publish, downloads the latest tarball, inserts itself, bumps the patch version, and republishes. One stolen identity becomes many malicious releases.
4. The persistence is dev-tool specific. The worm uses stolen GitHub tokens to inject files into Claude and Visual Studio Code configuration paths, including .claude/settings.json and .vscode/tasks.json. Future Claude or VS Code activity in the repository restarts the payload. This is the first widely-reported worm that uses an AI coding tool's config file as a persistence layer.
The 48-hour SMB response playbook
If you are an SMB or MSP and you learned about ChainDrop on Monday morning, this is the order I would do the work in. None of it requires a new vendor.
Day 1 morning: identify your exposure
Pull the list of every npm package you or your developers publish or have published in the last 12 months. For each, check whether any of the 400+ compromised packages is in the dependency tree. The npm CLI audit command against your lockfile is the fastest first pass. If you are not using lockfiles, start. The package-lock.json is the only record of what you actually installed.
For each developer workstation and CI/CD runner that has run npm install against an affected package, treat the host as compromised. The hosts that have only ever run installs against clean packages can be deprioritised but not declared clean until the credential audit is complete.
Day 1 afternoon: turn off lifecycle scripts in non-build environments
For developer workstations, sandbox runners, and any environment that does not compile native modules, set the npm config to ignore lifecycle scripts by default.
npm config set ignore-scripts true
The same flag exists in pnpm and yarn. In CI, use npm ci --ignore-scripts for installs where you do not need native compilation, and run a separate explicit step for the few packages that genuinely need a build. The preinstall script is the worm's entry point. Disabling it by default is the single biggest fix an SMB can ship this week.
The trade-off is that some packages genuinely need lifecycle scripts to work. esbuild, sharp, and node-gyp native modules will not install without them. The fix is a small allowlist of the packages that need scripts, scoped per environment, with the default set to "no scripts". For most developer workflows, this default is safe.
Day 2 morning: the 24-hour credential audit
For every host you identified as exposed, revoke every credential that host could reach. The list is longer than most teams expect. It includes:
- The developer's GitHub personal access token and OAuth grants
- The developer's npm publish tokens and any maintainer tokens for the packages they own
- The CI/CD runner's OIDC trust and the AWS, GCP, and Azure roles it can assume
- Any local AWS access keys, kubeconfig contexts, or HashiCorp Vault tokens on the workstation
- The developer's session cookies and refresh tokens for the SaaS tools they were logged into
- SSH keys that lived on the workstation, including ones the developer forgot they had
Revoke from a known-clean machine. Do not run revocation commands from the host you are auditing. After revocation, rebuild the host from a trusted base image. Do not try to "clean" a compromised developer workstation. Rebuild it.
Day 2 afternoon: hunt the secondary infection path
Audit your GitHub repositories for the four files the worm injects: .claude/settings.json, .claude/setup.mjs, .vscode/tasks.json, and .vscode/setup.mjs. Microsoft's analysis names these paths explicitly. The legitimate versions of these files exist, but the malicious versions appear in repositories that have not been touched in weeks, often without a matching commit from a trusted author.
For each repository, run git log --all -- .claude/settings.json .claude/setup.mjs .vscode/tasks.json .vscode/setup.mjs and review the recent history. Any commit from an unfamiliar author, or any commit that introduces content you did not write, is a candidate. Roll the file back from a known-good commit and rotate the repository's deploy keys and GitHub Actions secrets.
If you use GitHub secret scanning, turn on the partner-pattern set so that npm, AWS, and HashiCorp tokens are flagged the moment they appear in a commit.
Why segmentation matters more than detection in this campaign
Self-propagation changes the response model. In a normal breach, the attacker needs to manually pivot from the initial foothold. In a worm, the pivoting is automated. Every minute between detection and containment is multiplied by the number of hosts the worm can reach.
For an SMB, the segmentation that matters is credential scoping, not network microsegmentation. One npm token can publish 50 packages. One GitHub token can write to 30 repositories. One AWS key can enumerate every S3 bucket in the account. If those credentials are scoped to the single workflow that needs them, the worm spreads one package, not 50.
The 30-minute credential-scoping audit is the cheapest insurance policy in this whole incident:
- npm publish tokens should be per-package, not per-account.
- GitHub Actions OIDC trust should be per-workflow, per-repository, not tenant-wide.
- AWS, GCP, and Azure roles should be per-workload, with explicit deny rules for high-privilege actions.
- The npm
prepublishOnlyandpostpublishscripts should not run on tokens that can also access cloud credentials.
Microsoft's Zero Trust guidance is the longer-form reference.
The detection queries if you have Microsoft Defender XDR or Sentinel
Microsoft published a set of advanced hunting queries in the same advisory. The one most useful for an SMB is the process-creation query that looks for the obfuscated Bun runtime launching from node_modules paths. Run it against the last 30 days of DeviceProcessEvents in Microsoft Defender XDR, or the equivalent Process table in Sentinel.
If you do not have Defender XDR, the equivalent audit for a smaller stack is to enumerate every process on every developer workstation that ran from a path under node_modules/.bin/ or node_modules/*/setup.mjs in the last 30 days. The Bun runtime is unusual in a Node project. Anything invoking it is worth a manual look.
Save the output as evidence. A single hit is a credential rotation. Multiple hits across hosts is a full incident. The CISA Known Exploited Vulnerabilities catalog is not the right home for ChainDrop. ChainDrop is a worm, not a CVE. The operating principle from CISA's KEV guidance still applies: known exploitation should trigger an exception to the normal patch rhythm, and the "patch" here is a credential rotation and a host rebuild.
The rollout checklist for the rest of the week
- Pull every npm package you or your developers publish. Cross-check against the 400+ compromised list in the Microsoft advisory.
- Run
npm auditagainst everypackage-lock.jsonin your repositories. Save the output as evidence. - Set
npm config set ignore-scripts trueon every developer workstation and sandbox runner. - For each affected host, revoke the credentials in the list above. Rebuild the host from a trusted base image.
- Audit
.claude/settings.json,.claude/setup.mjs,.vscode/tasks.json, and.vscode/setup.mjsin every repository you own. Roll back any unfamiliar commit. - Turn on GitHub secret scanning partner patterns for npm, AWS, GitHub, and HashiCorp tokens.
- Replace account-wide npm publish tokens with per-package granular access tokens.
- Tighten GitHub Actions OIDC trust to the per-workflow, per-repository shape. The
permissions:block should be the minimum the workflow needs. - Run the Microsoft Defender XDR hunting query against the last 30 days of process telemetry.
- Brief the development team on the
preinstallscript default and why the build environment is now opt-in. - Add a 7-day rolling audit of npm publishes your maintainers own. A patch release you did not push is the early warning.
FAQ: ChainDrop questions ANZ IT-pros actually ask
My developers do not publish npm packages. Are we in scope?
Probably yes. The worm's entry point is npm install, which every developer runs daily. The publishing-token theft is the worm's spread mechanism, not its entry point. Your developers do not need to maintain packages to be exposed.
Why does Microsoft call it a Mini Shai-Hulud variant?
Shai-Hulud was a self-propagating npm worm first reported in 2024. ChainDrop is a smaller, more focused variant of the same family. The propagation mechanics and the exfiltration chain are the same shape. The Mini prefix is about payload size, not threat size.
Should we move off npm to a private registry?
Not as a primary defence. A private registry narrows the supply chain but does not stop the same worm if a single private token is stolen. The fix is lifecycle-script control, per-package tokens, and credential scoping, all of which work equally well against the public registry and a private one.
What about npm ci instead of npm install?
npm ci is better hygiene. It installs from the lockfile and refuses to mutate it, which means a maliciously-modified package.json cannot add new dependencies. Pair it with --ignore-scripts in non-build environments and you have a credible default for the developer fleet.
What is the smallest audit that catches a worm like this for an SMB without a SOC?
Three checks. The git log audit on the four dev-config file paths in your repositories. The process-creation hunt for the Bun runtime under node_modules/. The 30-day rolling audit of npm publishes your maintainers own. Each takes under an hour for a small team. None of them need a SOC to run.
Further Reading
- ChainDrop supply chain compromise: Anatomy of a self-propagating worm - Microsoft Security Blog (Microsoft, 4 Aug 2026)
- npm audit - npm Docs (npm, current)
- npm ci - npm Docs (npm, current)
- npm install - npm Docs (npm, current)
- npm config - ignore-scripts (npm, current)
- GitHub Actions security hardening (GitHub Docs, current)
- Managing your personal access tokens - GitHub Docs (GitHub Docs, current)
- About secret scanning - GitHub Docs (GitHub Docs, current)
- Understanding your software supply chain - GitHub Docs (GitHub Docs, current)
- Microsoft Zero Trust guidance (Microsoft Learn, current)
- CISA supply chain risk management (CISA, current)
- CISA Known Exploited Vulnerabilities catalog (CISA, current)
- NCSC UK - Supply chain security collection (NCSC, current)
- ACSC Essential Eight maturity model (ACSC, current)
- MITRE ATT&CK - Lateral Movement (TA0008) (MITRE, current)
- OWASP Top 10 (OWASP, current)
- Your vendor's helpdesk is now a breach vector - SecureInSeconds (July 2026)
- MFA fatigue: the 30-day playbook for ANZ SMB IT-pros - SecureInSeconds (August 2026)
- Patch Tuesday August 2026: the ANZ SMB priority list - SecureInSeconds (August 2026)
- The Frontier Airlines breach shows the supply chain problem - SecureInSeconds (July 2026)
- When an AI agent escaped an eval and got RCE - SecureInSeconds (July 2026)
- Your AI agent runs as you - SecureInSeconds (July 2026)
- Three claimed CISA KEV additions: the IT-pro verification and triage checklist - SecureInSeconds (July 2026)
If you run a development team, a build environment, or a CI/CD fleet for an SMB, forward this to the person who owns the npm publish tokens. The audit takes an afternoon. The credential rotation takes a day. The cost of either is much smaller than the cost of finding out about the worm from a customer.
Mathew Clark
Founder, SecureInSeconds
Currently: running npm audit against a package-lock.json I have not opened in nine months, with a sticky note that says "rotate every npm token" in the margin.



