A self-replicating worm has been moving through the npm registry since September 2025, and the variant researchers were writing about last month scans 469 hardcoded locations on an infected machine looking for credentials. The earlier open-source version checked 189. What it is looking for has changed as much as how many places it looks: alongside npm tokens, GitHub personal access tokens and cloud keys, it now enumerates API keys for OpenAI, Anthropic, Claude, Cursor, Codex and Gemini by name. If your agency runs npm install anywhere in a build pipeline, including for something as ordinary as compiling theme assets for a WordPress or Drupal site, you are inside the npm supply chain blast radius, and the reason is more mechanical than most coverage explains. This piece covers how the worm actually propagates, what the 469 figure counts and what it does not, why model provider keys are now on the list, why a CMS build pipeline is exposed at all, what npm and GitHub have changed in response, and what to do this week.
The short version: the payload executes during installation, before your build script runs, with whatever environment variables your CI job holds. Everything else follows from that one fact.
What the npm supply chain worm actually does
The propagation mechanism is the part worth understanding, because it explains why the blast radius grows on its own.
The worm was first documented in mid-September 2025 by ReversingLabs researcher Karlo Zanki, who described it as a first of its kind self-replicating worm. CISA’s alert of September 23, 2025 describes the loop plainly: the malware "leveraged an automated process to rapidly spread by authenticating to the npm registry as the compromised developer, injecting code into other packages, and publishing compromised versions to the registry." CISA put the first wave at over 500 packages.
So it does not need a human operator between victims. It steals a maintainer’s publish token, republishes trojanized versions of every package that maintainer owns, and each of those packages carries the same loop to the next maintainer who installs one.
The execution trigger is a package lifecycle script. Palo Alto’s Unit 42 traced the mechanism at code level: the malware downloads a package tarball, modifies package.json, injects a script, repacks and republishes. In the original wave that script ran on postinstall. In the November 2025 wave it moved to preinstall, which Unit 42 says "dramatically widened the area of impact across developer machines and continuous integration and continuous delivery (CI/CD) pipelines."
That shift is the whole story for anyone running a build server. On preinstall, the payload runs before your build command, before your tests, before anything you wrote. Installing the dependency is sufficient.
What the 469 figure counts, and what it does not
Two clarifications the coverage tends to skip.
The number comes from GitGuardian, in a post by Gaetan Ferry published on August 7, 2026, which states that the malware "now scans 469 secret locations, including AI agents, crypto wallets, and CI/CD tools," against "a list of 189 hardcoded locations" in the open-source version. The arithmetic in the post’s own title is 280 new places. The Hacker News reported it again on September 3, which is where most people encountered it, but the research is a month old.
And these are locations, not stolen secrets. The figure counts file paths and configuration locations the scanner is hardcoded to check: .env files, shell history, package manager configs, CLI credential caches, IDE settings, AI tool configs. It tells you how thoroughly the thing searches, not how much it found.
One more piece of precision. The 469-location variant belongs to what GitGuardian and JFrog track as a related but separate lineage seeded through the keyv and cacheable packages in August 2026, not literally the same binary as the September 2025 original. JFrog counted over 400 compromised packages across more than 1,700 versions in that wave. Treating every wave as one continuous artifact will get details wrong.
It now knows what an AI key is worth
This is the part that has not traveled, and it is the most consequential change.
JFrog’s analysis of the August 2026 wave found it targeting credentials for OpenAI, Anthropic, Claude, Cursor, Codex and Gemini, named explicitly. Separately, Socket documented a variant it calls SANDWORM_MODE in February 2026, which it places in the same family and which "harvests API keys for nine LLM providers, OpenAI, Anthropic, Google, Groq, Together, Fireworks, Replicate, Mistral, and Cohere, from environment variables and .env files."
Socket also documented something stranger in that variant: it plants a malicious Model Context Protocol server whose tool descriptions carry prompt injection, written to direct AI coding assistants to read SSH keys, cloud credentials and npm tokens without the developer noticing. The assistant becomes the exfiltration path.
We made the argument in our piece on self-hosted AI tooling holding credentials worth more than the host. This is the same conclusion arrived at from the opposite direction. There the attacker walked in through an exposed web application. Here they arrive inside a dependency you asked for. The asset they want is identical, and most coverage still describes this worm as an npm token stealer.
Why a WordPress or Drupal shop is exposed
The instinct is that this is a JavaScript problem for JavaScript teams. It is not, and the reason is boring.
A great many WordPress and Drupal builds run npm somewhere. Compiling Sass, bundling block editor assets, running a build step for a custom theme, generating a headless front end. That build usually runs in CI, and a CI job holds credentials by design: a deploy key, a hosting provider token, cloud credentials, a registry token. With preinstall execution, a compromised dependency anywhere in your tree, including several levels deep in transitive dependencies you have never heard of, runs with all of it.
FortiGuard Labs published an incident on June 26, 2026 that shows the shape of it: a compromised dependency executing during installs or CI jobs, credentials harvested from a Jenkins host through the cloud instance metadata service, then those pipeline credentials used to escalate privileges and reach a data warehouse. Fortinet’s own summary of the lesson is the line to keep: pipeline identity equals production identity.
Be careful with that example, though. Fortinet itself says there is "no definitive proof that the worm infection caused the cloud compromise," and rests the connection on timing and technique rather than a traced chain from a specific package. It illustrates the exposure path. It does not prove this worm walked it.
What npm and GitHub actually changed
More than most vendors do, and with unusual candor about why.
GitHub published its response on September 23, 2025, opening with the admission that "in direct response to this incident, GitHub has taken swift and decisive action." The changes: classic tokens deprecated, time-based one time password two-factor moved to FIDO, granular publish tokens cut to a seven-day lifetime, publish access set to disallow tokens by default, the option to bypass two-factor for local publishing removed, and trusted publishing expanded so that packages can be published through short-lived OIDC credentials with no stored token at all. Packages published that way carry provenance attestations, which is cryptographic proof of where and how they were built.
The larger change came later. npm 12, announced in June 2026, stops running preinstall, install and postinstall scripts from dependencies unless a project explicitly allows them. That removes the execution trigger this entire class of attack depends on. Worth noting honestly: the announcement does not name this worm as the reason, so the causal link is ours to infer rather than GitHub’s to state.
What to do this week
Turn off lifecycle scripts and see what breaks. npm config set ignore-scripts true, then find out which of your dependencies genuinely needed a build step. This is the single control that neutralizes the mechanism, and on most CMS asset pipelines the answer is that almost nothing needed it. It is community practice rather than an npm mandate today, but npm 12 makes it the default, so you are moving early rather than off-piste.
Stop putting production credentials in build jobs. A pipeline that deploys needs a deploy credential scoped to deploying. If the same job also holds a cloud administrator key or a model provider key, that is the finding.
Put spending limits on model provider keys, and keep the keys used by developer tooling separate from the ones your product runs on. A harvested key with no cap is an open budget.
Move to trusted publishing if you publish anything. It removes the long-lived token that makes the propagation loop work, and it is the reason this attack cannot replicate through a maintainer who uses it.
Rotate what was exposed rather than what you think was stolen. The documented behavior is exhaustive scanning of credential locations. If a runner touched a compromised install, treat everything in that environment as disclosed, in the same way we argued for registry proxy credentials.
Frequently Asked Questions
What is the npm supply chain worm?
A self-replicating worm first documented in September 2025 by ReversingLabs. It steals a maintainer’s npm publish token, republishes trojanized versions of every package that maintainer owns, and executes on the next victim through a package lifecycle script. CISA put the first wave at over 500 packages.
What does the 469 number mean?
It is the count of hardcoded locations the malware’s scanner checks for credentials, per GitGuardian research published August 7, 2026, up from 189 in the open-source version. It counts places searched, not secrets found, and it describes a variant lineage seeded through the keyv and cacheable packages rather than the original September 2025 worm.
Does it target AI API keys?
Yes, explicitly. JFrog found the August 2026 wave targeting credentials for OpenAI, Anthropic, Claude, Cursor, Codex and Gemini by name. Socket documented a related variant harvesting keys for nine LLM providers from environment variables and .env files, and planting a malicious MCP server with prompt-injected tool descriptions aimed at AI coding assistants.
Why does this affect a WordPress or Drupal site?
Because the build does. Compiling theme assets, bundling block editor JavaScript or building a headless front end usually means npm running in CI, and lifecycle scripts execute with that job’s full environment. The CMS is not the target. The build server’s credentials are.
Does the payload run before my build script?
On preinstall, yes. Unit 42 documented the shift from postinstall to preinstall in the November 2025 wave and said it dramatically widened impact across developer machines and CI/CD pipelines. Installing the dependency is enough; nothing you wrote has to run.
Are transitive dependencies a risk, or only direct ones?
Both. Lifecycle scripts run for dependencies at any depth, and the August 2026 wave was seeded through keyv and cacheable, which most affected projects would have had indirectly rather than by choice.
What is the single most effective mitigation?
Disabling lifecycle scripts, because it removes the execution trigger rather than trying to detect the payload. npm 12 makes this the default by no longer running preinstall, install or postinstall scripts from dependencies unless a project allows them.
What did GitHub change?
After the September 2025 wave it deprecated classic tokens, moved to FIDO two-factor, cut granular publish token lifetime to seven days, set publish access to disallow tokens by default, removed the two-factor bypass for local publishing, and expanded trusted publishing with provenance attestations so packages can be published without a stored token.
Is the Node.js malware loader story the same thing?
No, and they should not be merged. Symantec reported in September 2026 that attackers are abusing the legitimate signed node.exe binary to run malicious JavaScript and evade signature detection. That abuses the official Node.js runtime as a living-off-the-land loader. It has nothing to do with npm registry compromise.
Should I rotate credentials if I am not sure I was affected?
If a build runner installed dependencies during an affected window, yes. The documented behavior is exhaustive scanning of credential locations rather than targeted theft, so uncertainty about what was taken is not a reason to defer rotation of what was present.
Compliance note. The propagation mechanism and package counts are quoted from CISA’s alert, Unit 42, Datadog, Wiz and JFrog, each reporting its own research. The 469 and 189 figures are GitGuardian’s, published August 7, 2026 and re-reported on September 3. The AI credential targeting is JFrog’s and Socket’s. The FortiGuard incident is presented as illustrative because Fortinet itself states there is no definitive proof the worm caused that cloud compromise. GitHub’s platform changes are quoted from its own post; the connection between npm 12 disabling install scripts and this attack is our inference, since the announcement does not name it.