The discovery of a self-propagating npm worm linked initially to the popular Keyv package demonstrates how quickly a compromised developer account or software-publishing workflow can spread malicious code across the open-source ecosystem.
The campaign first attracted attention after attackers published `keyv@6.0.0` with a malicious pre-installation script. Keyv is a widely used JavaScript key-value storage library that supports several database and caching backends. Because it appears deep within many dependency trees, developers may install it without selecting it directly.
The attack rapidly expanded beyond Keyv and the related Cacheable packages. Researchers identified poisoned versions across hundreds of package names maintained by several unrelated organizations. The timing and publishing patterns indicated automated propagation, with one compromised publishing identity apparently leading to additional packages and organizations being affected within minutes.
This was not merely a case of attackers adding malware to one popular library. The malicious code was designed to steal the credentials needed to compromise more repositories and npm packages, allowing each infected development environment to become a possible source of further infections.
That self-replicating behaviour makes the incident considerably more dangerous than an ordinary malicious-package campaign.
The malicious code executed before the application started
The poisoned packages added a `preinstall` command that launched a file called `setup.mjs`. npm lifecycle scripts can run automatically when a package is installed, before the developer’s own application code begins executing.
This means the victim did not need to import Keyv, call one of its functions or start the project. Simply running an installation command that resolved to an affected version could activate the malicious payload.
The attack could therefore affect developer workstations, automated build servers and CI/CD runners. These systems frequently install dependencies as part of normal development, testing and deployment processes, making package installation an attractive execution point for attackers.
A developer may believe that `npm install` is merely downloading reusable code. In reality, lifecycle scripts can execute commands using the permissions and credentials available to the user or automation account performing the installation.
The malicious release left the compiled Keyv library code largely unchanged. Instead, the attackers added two files and one line to the package scripts. This helped preserve the package’s expected functionality and kept the malicious change small enough to escape casual review.
The application could therefore continue working normally while the installation process quietly compromised the underlying development environment.
The malware brought its own runtime
The initial script checked whether the Bun JavaScript runtime was available on the infected system. If Bun was not installed, the malware downloaded the required version from Bun’s legitimate GitHub releases and used it to execute a large compiled payload.
This technique reduced the attacker’s dependence on software already present on the victim’s machine. The absence of Bun did not stop the attack because the loader obtained the exact runtime it required.
Using an official GitHub release also made network detection more difficult. A development system communicating with GitHub is not inherently suspicious, and many organizations permit such connections without restriction.
Security tools relying on malicious-domain reputation might therefore see only traffic to legitimate GitHub infrastructure during the initial execution stage.
This demonstrates an important limitation of destination-based security controls. A trusted service can distribute legitimate software that an attacker then uses to support malicious activity.
Defenders must evaluate the complete context, including which process initiated the download, why the runtime was required and what code executed immediately afterward.
A package installation process unexpectedly downloading a separate runtime and launching a large obfuscated bundle deserves investigation, even when the files originate from an established software project.
Developer and CI/CD secrets were primary targets
The payload was designed to collect an extensive range of credentials from the infected system and its surrounding environment.
Its targets reportedly included GitHub tokens, npm publishing tokens, AWS access keys, Google Cloud service-account credentials, Microsoft Azure secrets, Stripe keys, Vault tokens, Kubernetes service-account tokens, database connection strings and private cryptographic keys.
The malware also attempted to retrieve credentials from cloud metadata services. This could expose temporary roles assigned to cloud virtual machines, containers or CI/CD runners even when no permanent key was stored on disk.
Such credentials may provide access far beyond the initially infected endpoint. A GitHub token can expose private repositories, organization settings and CI workflows. An npm token may allow attackers to publish malicious versions of legitimate packages. Cloud credentials can provide access to production workloads, storage services and sensitive business data.
Database connection strings may reveal usernames and passwords for MongoDB, MySQL, PostgreSQL or Redis systems. Private keys could provide access to servers, signing systems or encrypted information.
This is why developer endpoints are particularly attractive targets. They often function as bridges between source code, cloud platforms, package registries and production infrastructure.
Compromising one developer can give an attacker access to several otherwise separate environments.
GitHub Actions runner memory was searched for secrets
The malware reportedly included functionality specifically designed to steal credentials from GitHub Actions runners.
Rather than relying only on environment variables or files, it searched the Linux process list for the GitHub Actions runner worker and attempted to read secret values directly from the process memory.
This matters because organizations often assume that masking secrets in CI logs or limiting their visibility to individual workflow steps provides sufficient protection.
A malicious process running with appropriate permissions on the same runner may be able to inspect the memory of the worker process and recover secrets even when they are never printed.
The campaign therefore demonstrates why self-hosted and long-lived CI runners create significant security risk. Malware introduced during one build may remain active, inspect later jobs and access credentials belonging to unrelated repositories or deployment processes.
Ephemeral runners can reduce this risk by creating a clean environment for each job and destroying it afterward. However, even an ephemeral runner can expose secrets used during the malicious job itself.
Organizations should therefore avoid providing sensitive credentials during dependency installation unless they are absolutely required.
Build stages that install untrusted third-party packages should be separated from stages that access production secrets, signing keys or publishing tokens.
The worm could publish malicious versions of additional packages
The payload reportedly contained npm publishing functionality that could identify packages accessible to a stolen npm account, modify them and publish poisoned versions.
This created the self-propagating characteristic of the campaign.
When malware executed in an environment containing an npm publishing token, it could use that token to compromise packages maintained by the victim. Developers or CI jobs that later installed those packages could expose more publishing tokens, allowing the infection to spread again.
Each compromised maintainer became a potential distribution channel.
This process transforms the dependency ecosystem into the attacker’s propagation network. The worm does not need to identify and attack every developer individually. It relies on the trust relationships already connecting package maintainers, dependencies, projects and automated build systems.
The speed of the publishing bursts supports the conclusion that much of the propagation was automated. Researchers observed entire package namespaces receiving poisoned releases within seconds.
Manual attackers might take hours to inspect an account and alter individual projects. Automated malware can enumerate everything available to a token and publish malicious versions almost immediately.
By the time the first package is recognised as compromised, several downstream organizations may already be affected.
The Keyv repository contained additional execution paths
The poisoned npm package was not the only route through which the payload could execute. Researchers also found malicious project configuration files committed to the Keyv source-code repository.
A `.claude/settings.json` file defined a Claude Code session-start hook that launched a script stored under the project’s `.vscode` directory. A corresponding Visual Studio Code task called a script under the `.claude` directory when the folder was opened.
Cross-referencing the directories made the configuration less obvious during casual inspection. A reviewer examining only one folder might not immediately see the full execution chain.
These hooks created a risk even for developers who did not install the affected npm package. Someone cloning the repository to inspect the incident or contribute to the project could potentially trigger the payload after trusting the workspace or allowing the project configuration.
Visual Studio Code applies workspace trust protections and generally prevents automatic tasks from running in an untrusted project. Claude Code also applies trust controls to project-supplied settings.
These controls reduce automatic exposure, but they still depend on users recognising the risk and refusing to trust a repository that appears legitimate.
A well-known open-source project with verified commits and familiar maintainers is exactly the type of repository a developer may approve without extensive scrutiny.
The incident therefore expands the software supply-chain threat beyond package installation. Repository configuration, editor tasks and AI coding-agent hooks can all become execution mechanisms.
AI coding tools have created another trusted automation layer
The use of Claude Code hooks is particularly significant because AI-assisted development tools are increasingly being granted the ability to read repositories, execute commands and modify source code.
Project-level configuration allows teams to automate useful setup and development tasks. However, it also gives a repository an opportunity to influence what the coding agent does after the project is opened.
Attackers can exploit this trust by adding hooks that appear to perform ordinary environment preparation while actually launching malicious scripts.
Developers may be more willing to approve these actions because the instructions appear to come from the repository rather than an unfamiliar external source.
Security controls must therefore include AI development agents in the same threat model as terminals, package managers and build systems.
Organizations should review repository-supplied AI-agent settings before allowing execution, particularly when cloning projects from external sources or responding to a public supply-chain incident.
AI tools should operate with restricted permissions and should not automatically inherit every token, SSH key and cloud credential available in the developer’s ordinary shell environment.
A coding assistant does not require unrestricted access to production infrastructure merely because it has developed strong opinions about refactoring.
Valid provenance did not mean the package was safe
The poisoned Keyv release reportedly carried valid OpenID Connect and SLSA provenance because it was built and published through the project’s legitimate GitHub Actions workflow.
The attestation correctly demonstrated which repository, workflow and build process produced the release. However, it could not establish that the source code entering that process was trustworthy.
This distinction is critical.
Software provenance can prove that an artifact came from an approved build pipeline without proving that the pipeline account, repository or source code had not been compromised.
In this incident, the legitimate release system faithfully built and signed malicious source. The provenance was valid because the compromised process operated through the expected infrastructure.
Organizations should not treat a verified provenance badge as a guarantee that a package is free from malicious code.
Provenance helps prevent attackers from substituting an unrelated binary after the build. It does not protect against attackers who gain control before or during the trusted build process.
Security teams must combine provenance with source review, account security, behavioural analysis and monitoring of unusual publishing activity.
Verified commits can also be misleading
One of the malicious commits that planted the Claude Code and Visual Studio Code hooks displayed a verified GitHub signature and identified `github-actions[bot]` as its author.
A green verified badge can create a strong appearance of legitimacy, but it does not necessarily prove that the expected human or automation system intentionally made the change.
Commits created through GitHub’s API or web interfaces may be signed by GitHub while allowing the caller to supply author information. An attacker with a stolen token or authenticated session may therefore create a cryptographically valid commit that appears to come from a trusted bot.
The signature proves that GitHub signed the commit through an accepted mechanism. It does not prove who controlled the credential used to submit it or whether the change was authorised.
Code reviewers should therefore evaluate what a commit does rather than relying on its badge, author name or routine-looking message.
A verified commit adding editor tasks, lifecycle scripts and large obfuscated files should receive the same scrutiny as an unsigned change.
The campaign deliberately exploited the human tendency to treat familiar automation as harmless.
Credential revocation could trigger attacker-controlled code
One of the most unusual features identified in the payload was a credential-revocation watcher.
The malware reportedly stored a stolen GitHub token and checked periodically whether the token remained valid. When the token began returning an authentication error, indicating that it had been revoked, the watcher executed an attacker-supplied local command.
This behaviour functions like a dead-man’s switch. The normal incident-response action of revoking the stolen token could trigger additional malicious activity on the infected machine.
The specific command may vary, but the mechanism can support destructive actions, additional malware execution or attempts to interfere with remediation.
This changes the safe order of response.
Security teams should first isolate the affected machine and identify and remove the token-monitoring persistence before rotating the credentials it watches.
Rotating tokens while the malware remains active may notify the payload that defenders have discovered the compromise and cause it to execute its handler.
The watcher reportedly used user-level persistence mechanisms on macOS and Linux, allowing it to survive logout or restart during its active period.
Responders should search for unfamiliar Launch Agents, systemd user services, scripts and configuration directories associated with GitHub token monitoring before beginning widespread credential replacement.
This does not mean credential rotation should be delayed unnecessarily. It means rotation should occur from a clean environment after the malicious watcher has been neutralised.
The malware avoided conventional command-and-control infrastructure
The campaign reportedly did not rely on a traditional dedicated command-and-control domain.
Instead, the malware used GitHub repositories and GitHub Actions artifacts as channels for storing or retrieving stolen information. Exfiltrated data was encrypted before being uploaded.
Abusing GitHub provided several advantages. Developer and CI environments commonly communicate with GitHub, so the traffic may not appear unusual. Blocking the entire platform would also be impractical for many organizations.
Traditional threat intelligence focused on identifying suspicious domains or IP addresses may therefore provide limited protection.
The attack used trusted services for runtime downloads, publishing, repository access and data transfer. Each individual connection could resemble ordinary development activity.
Detection requires understanding behaviour rather than relying solely on reputation.
A package installation that reads private keys, accesses cloud metadata, creates unexpected repositories and uploads encrypted archives to GitHub is suspicious even though GitHub itself is legitimate.
Organizations should monitor the actions performed through trusted platforms, including creation of new repositories, unfamiliar workflow artifacts, unusual token use and bulk package publishing.
Some poisoned packages were development dependencies
Several affected packages reportedly provided ESLint, Babel, Jest, Prettier and other developer-tooling configurations.
These packages may be installed only as development dependencies and never included in the production application.
That does not make them low risk.
Development dependencies execute on developer laptops and CI runners, which are precisely the environments likely to contain repository tokens, cloud credentials and package-publishing access.
A package does not need to reach the production runtime to compromise the software supply chain. It may instead manipulate the source, build process or release credentials before the application is produced.
Security assessments should therefore inspect all dependencies, including test libraries, formatting configurations and build tools.
Organizations sometimes focus vulnerability scanning on packages included in production artifacts while giving less attention to development tooling. This campaign demonstrates that dev dependencies may provide attackers with an even more valuable environment.
The developer machine and CI pipeline are where trusted software is created. Compromise there allows attackers to affect everything produced afterward.
Latest package tags cannot be trusted during a fast-moving incident
As maintainers and npm responded to the campaign, malicious versions were removed, older versions were restored as `latest` and new findings continued to emerge.
This makes a static list of currently affected package tags unreliable.
A package that appears clean today may have resolved to a poisoned version when a lockfile was generated earlier. Conversely, blocking an entire namespace may incorrectly classify unaffected versions as malicious.
Organizations should examine the exact package name and resolved version stored in project lockfiles and package-manager caches.
The relevant question is not which version npm currently presents as the default. It is which artifact the affected system installed and whether its lifecycle script executed.
Dependency inventories and software bills of materials should record exact versions and integrity hashes. Without this information, organizations may struggle to determine whether a particular build or workstation was exposed.
CI logs, package caches and build artifacts can help reconstruct which versions were resolved during the incident window.
Simply running another installation after the malicious tag has been removed does not prove that the earlier environment remained safe.
Uninstalling the package is not sufficient
Any workstation or CI runner that executed an affected version should be treated as potentially compromised.
Removing the dependency or replacing it with a clean version does not undo credential theft, repository modification, persistence or additional malicious packages published through stolen tokens.
The infected machine should be isolated from the network while evidence is collected. Responders should search for the malicious setup files, Bun-compiled payload, token watcher, editor hooks and unexpected services or startup entries.
Security teams should review GitHub and npm activity associated with credentials available on the system. New package releases, repository changes, workflows, tokens and unfamiliar sessions should be investigated.
Cloud accounts should be examined for access using exposed keys or temporary roles. Kubernetes clusters, Vault systems and databases may also require review depending on the credentials present.
Where system integrity cannot be established confidently, rebuilding the workstation or runner from a trusted image is safer than attempting limited cleanup.
Developer devices contain too many high-value secrets to accept an uncertain remediation result merely because reinstalling the operating system is inconvenient.
Credential rotation must be comprehensive
After the malicious persistence has been removed, organizations should rotate every credential that may have been accessible to the affected environment.
This includes GitHub tokens, npm tokens, cloud access keys, database credentials, SSH keys, private certificates, Vault tokens, Kubernetes service-account credentials and payment-platform secrets.
Active sessions should also be revoked because password rotation may not invalidate every token or authenticated device.
Organizations should review whether the compromised token had access to organizational secrets, repository secrets or publishing workflows. The investigation must follow the permissions of the credential rather than stopping at the infected machine.
npm tokens with publishing rights require particular attention because they may have been used to poison additional packages. Maintainers should inspect publication histories for unexpected versions and coordinate removal with the registry.
GitHub repositories should be checked for unknown commits, workflow files, deploy keys, hooks, new collaborators and public repositories created as data-dead drops.
Signing keys and release credentials accessible to affected CI systems may also need replacement. Software produced during the exposure period should be reviewed before it continues to be distributed.
Lifecycle scripts should be restricted
npm 12 introduces controls that block unapproved dependency lifecycle scripts by default, reducing automatic exposure to malicious `preinstall`, `install` and `postinstall` commands.
Organizations using earlier npm versions should consider installing dependencies with scripts disabled where operationally possible.
However, some legitimate packages require lifecycle scripts to compile native modules or perform setup. Completely disabling them may break builds and encourage developers to bypass the policy.
A stronger approach is to allow scripts only for reviewed packages and require security approval when a dependency adds or changes an installation hook.
Package updates introducing a new `preinstall` command should receive immediate scrutiny, particularly when the package did not previously require one.
CI pipelines should separate dependency retrieval from execution and run untrusted installation stages inside restricted containers or disposable environments.
Network access should be limited during installation so that packages cannot freely contact cloud metadata services, internal networks and arbitrary internet destinations.
Developer credentials should not be automatically available to every installation script merely because npm happens to be running in the same shell.
Publishing credentials require stronger protection
npm publishing tokens should be short-lived, narrowly scoped and unavailable during ordinary development and testing.
Projects should use trusted publishing through tightly controlled CI workflows rather than storing long-lived npm tokens on developer laptops.
Trusted publishing does not eliminate repository or pipeline compromise, as the Keyv incident demonstrates, but it reduces the opportunity for malware on a random developer workstation to publish releases directly.
Release workflows should require protected branches, reviewed changes and explicit approval before publishing sensitive packages.
Organizations should monitor for unusual publishing bursts, rapid version increments and releases outside established schedules.
Publishing an entire namespace within seconds is not normal maintainer behaviour and should trigger automatic suspension or verification.
Registry platforms can reduce worm propagation by detecting when one identity begins publishing modified versions of many packages immediately after receiving new credentials or changing its authentication pattern.
Software ecosystems must design controls for automated compromise because automated publishing has allowed attackers to move faster than human maintainers can respond.
AI-agent and editor configuration must be reviewed
Repository security scanning should include `.claude`, `.vscode`, `.github` and other configuration directories that can execute commands.
These files are often ignored during code review because they are considered development conveniences rather than application logic.
However, editor tasks, AI hooks and CI workflows may execute with access to the developer’s local files and credentials.
Organizations should define policies that prevent automatic execution of repository-supplied tasks without explicit approval.
Developers investigating a compromised project should open the source in a restricted environment rather than trusting it on their ordinary workstation.
The mere act of opening a repository should not be allowed to expose production credentials or execute arbitrary code.
AI development tools should display clear warnings when project configuration introduces command hooks, particularly when the commands reference obfuscated or unexpectedly large files.
As development automation becomes more capable, project metadata increasingly becomes executable infrastructure. Security reviews must evolve accordingly.
The broader cybersecurity lesson
The Keyv-linked npm worm demonstrates how software supply-chain attacks are evolving from isolated package compromises into automated credential-driven epidemics.
The attackers used one poisoned release to steal publishing credentials, compromise additional packages and expand into multiple organizations within minutes.
They also targeted CI runner memory, cloud credentials, private keys, editor tasks and AI coding-agent hooks, showing a detailed understanding of modern development environments.
The incident exposes several uncomfortable truths about current software trust models.
A valid provenance record can authenticate a malicious build. A verified commit can be submitted using a stolen credential. A legitimate GitHub connection can carry stolen data. A harmless-looking development dependency can execute before the application starts.
None of these signals is useless, but none is sufficient by itself.
Effective protection requires layered controls around developer identities, package installation, release pipelines, repository configuration and credential use.
Organizations should know exactly which dependencies they install, restrict lifecycle scripts, use isolated CI runners, remove long-lived publishing tokens and monitor unusual changes across package registries and source repositories.
Developer workstations must be treated as privileged systems because they hold the credentials and trust required to create and distribute software.
The response to an affected package must also extend beyond uninstalling it. Systems that executed the payload may have exposed credentials, altered repositories and created new malicious releases that affect downstream users.
The most important lesson is that software supply-chain trust is transitive. A project trusts a package, the package trusts its maintainer, the maintainer trusts a development machine and the development machine trusts its tools and configuration.
The worm succeeded by moving through those trust relationships faster than defenders could verify them.
Open-source development depends on automation and shared components, but those efficiencies also create channels through which compromise can propagate at machine speed.
Security controls must therefore operate at the same speed. Package publishing, token use, repository changes and lifecycle-script execution require continuous monitoring and automatic containment when behaviour departs from established patterns.
Otherwise, one stolen developer credential can become hundreds of poisoned packages, thousands of exposed builds and an ecosystem-wide incident before most users have even learned that the first release was malicious.

A credential-stealing npm worm that first appeared in keyv@6.0.0 spread beyond the Keyv and Cacheable namespaces into hundreds of packages across multiple organizations on August 4, 2026. SafeDep verified 353 poisoned versions across 79 package names in the npm registry. Its monitoring put the wider footprint at 442 versions across 353 names, while Aikido later reported at least 868 packages
Source: Keyv-Linked npm Worm Poisons Hundreds of Packages, Plants Claude Code and VS Code Hooks via The Hacker News — published 04 Aug 2026.
Was this article helpful?
Your feedback helps us improve the knowledge base.