On August 4, 2026, a credential-stealing npm worm ripped through the JavaScript ecosystem in under four hours, poisoning packages that collectively handle over 500 million weekly downloads. The attack started with [email protected], a package sitting inside build chains from ESLint to cache-manager, and spread to 444 packages and 2,212 versions before anyone could stop it. The worm did not just steal npm tokens and cloud keys. It planted execution hooks inside Claude Code and VS Code configurations, turning the AI coding tools developers trust into a second-stage delivery mechanism. The Keyv npm supply chain attack is the most consequential package registry incident of 2026, and if you run JavaScript in production, it almost certainly hit your dependency tree.
The first confirmed malicious release was [email protected], published at 09:35 UTC. SafeDep verified 353 poisoned versions across 79 package names in the npm registry, with wider monitoring putting the footprint at 442 versions across 353 names. Aikido later reported at least 868 packages across 1,381 versions. StepSecurity's independent analysis counted 444 packages and 2,212 versions, including 433 additional packages the worm republished automatically using harvested CI credentials.
What happened during the four-hour npm worm window?
The attack unfolded in two waves. StepSecurity's timeline reconstruction shows the first wave between 09:35 and 10:14 UTC on August 4, hitting 11 verified full worm carriers in the jaredwray ecosystem. These included the most downloaded packages in the attack: [email protected] with 153,717,238 weekly downloads, [email protected] with 149,868,983, and [email protected] with 147,558,494.

The second wave began at 09:38 UTC. Using credentials harvested from the first victims, the worm republished itself into 433 more packages covering 2,201 versions. By 13:20 UTC, it had reached packages across at least a dozen organizations: @hubsync, @ornikar (42 packages), @arv-bedrock (5 packages), @deliveroo (2 packages), @picsart (2 packages), @onereach (78 packages), and @or-sdk (74 packages).
Every poisoned version followed the same infection pattern. The package manifest added node setup.mjs as a preinstall command, which downloaded the legitimate Bun JavaScript runtime as a dropper. That stager then loaded a 727,680-byte obfuscated payload called Math_Symbol.js that stole credentials, published more malicious packages, and burrowed into AI developer tooling. The worm spread through harvested CI credentials: when a pipeline installed a poisoned package, the preinstall script executed, the payload stole npm tokens and cloud credentials from the environment, and the worm used those credentials to publish new poisoned versions of other packages the victim maintained. Each new victim extended the chain.
How did the worm hide behind trusted provenance?
The most unsettling detail: the poisoned releases carried valid OIDC and SLSA provenance. The packages passed through the Keyv project's legitimate GitHub Actions release workflow, so the attestation correctly identified the build process. It could not establish that the source entering that process was safe.
JFrog's security research team confirmed that the malicious commit planting the Claude Code and VS Code hooks carried a green GitHub-verified badge with github-actions[bot] as the author identity. The verified badge proves GitHub signed the commit object. It does not prove who controlled the credential that submitted it.
This is the breakdown that should worry every team relying on signed commits and provenance attestations as a trust signal. The infrastructure worked as designed. The attestation was valid. The signature was real. The package was still malicious. SLSA provenance tells you a package was built through a specific pipeline. It does not tell you the code entering that pipeline was clean.
Snyk's analysis of the compromise noted that the maintainer behind keyv and the cacheable ecosystem should be treated as an incident victim. The compromise likely came through stolen credentials or a hijacked GitHub Actions workflow, not a willing insider. Wiz separately reported that the worm created GitHub repositories under compromised identities using default descriptions, a telltale of automated propagation.
Why do the Claude Code and VS Code hooks matter for your build?
The Keyv repository carried two execution paths that went beyond the npm install vector. JFrog found that .claude/settings.json contained a SessionStart hook calling node .vscode/setup.mjs, while .vscode/tasks.json defined an Environment Setup task with runOn: folderOpen calling node .claude/setup.mjs. Both setup files contained the Bun bootstrap. The file .claude/math_init.js was the worm itself.
Opening an infected repository in VS Code, or starting a Claude Code session in it, was enough to execute the payload, provided the user trusted the workspace or permitted the project configuration. This connects directly to our earlier coverage of AI coding agent malware hiding in clean GitHub repos: the attack surface is no longer just the package you install. It is the repository you open.
VS Code blocks automatic tasks in untrusted workspaces and prompts before allowing them by default. Claude Code applies workspace trust to repository-supplied project settings. Neither tool runs the hooks unconditionally. But both rely on the developer clicking through a prompt, and developers click through prompts all day.
The payload targeted three AI developer workflows: Claude Code, VS Code, and GitHub Copilot. If your team uses any of these tools with repositories pulled from npm packages or forks of compromised projects, the hooks represent a persistent re-infection vector that survives package cleanup. The ChainDrop worm's first wave already established that the Shai-Hulud lineage was evolving toward AI tooling. The August 4 attack is the proof that the evolution is operational, not theoretical.
What should you check in your lockfiles and CI right now?
The immediate priority is lockfile auditing. Do not rely on the headline package list alone. StepSecurity enumerated every affected name@version pair, and the worm republished historical versions of victim packages, not just the latest releases. A package that was safe yesterday may be poisoned today if the worm republished an older version with a higher semver or a dist-tag swap.
Concrete steps:
- Audit every lockfile for any package in the affected version set. The keyv, flat-cache, file-entry-cache, cacheable-request, cacheable, @cacheable/*, and cache-manager namespaces are the first tier. The 433 second-tier packages span @onereach, @or-sdk, @ornikar, @deliveroo, @picsart, and others.
- Rotate all credentials exposed to any CI pipeline that installed or built with these packages between 09:35 UTC on August 4 and the present. The payload harvested npm tokens, cloud provider credentials, and repository access tokens. Assume compromise if a poisoned package ran in your CI.
- Check repository configuration files for
.claude/settings.json,.vscode/tasks.json, and any file namedsetup.mjsorMath_Symbol.js. Remove them, and review git history for when they were added. - Pin and verify. Use
npm ciwith a known-good lockfile. Blockpreinstallandpostinstallscripts by default, and allowlist only packages that require them. - Rotate npm publish tokens for any maintainer account whose packages were in the affected set. The worm used harvested tokens to publish the second wave.
StepSecurity noted that at the time of its update, @picsart/[email protected] and @deliveroo/[email protected] were still live as latest in the npm registry. Cleanup was ongoing. If you depend on either package, treat the current version as suspect until npm confirms remediation.
What comes next for npm trust signals?
The ChainDrop worm exposes a gap that provenance attestation cannot close. SLSA and OIDC signing verify the build pipeline, not the source code. A compromised maintainer token or a hijacked GitHub Actions workflow produces a signed, attested, malicious package. The trust infrastructure says this came from the right pipeline when the right pipeline was the problem.
This attack also marks a shift in supply chain targeting. The worm went after AI coding agent configuration files, not just CI credentials. The addition of Ethereum blockchain C2, which StepSecurity calls EtherHiding, makes the command infrastructure harder to take down because it does not depend on a fixed domain or IP. The exfiltration is encrypted end to end, which means network monitoring alone will not catch the data leaving your environment.
The npm registry's response will determine how quickly the ecosystem recovers. Automated yanking of affected versions, dist-tag fixes, and maintainer credential resets are the table stakes. The harder problem is the 433 second-tier packages published with stolen credentials across dozens of organizations, each of which needs its own maintainer to confirm and remediate. Some of those maintainers may not yet know they were hit.
For builders, the lesson is that package trust is layered, and the layers are thinner than they looked. Provenance is necessary but insufficient. Install scripts are a privilege, not a right. And the next time you open a repository in your AI coding agent, the hooks in that repo are part of your attack surface.
