Safeguard
Threat Intelligence

Bring Your Own Runtime: Why the keyv Payload Downloaded Bun

The August 2026 npm worm did not run its second stage in Node. It downloaded a standalone Bun binary first — a choice that defeats a surprising amount of build-pipeline monitoring.

Nayan Dey
Senior Security Engineer
6 min read

Buried in the technical write-ups of the 4 August 2026 keyv and cacheable npm compromise is one implementation detail that deserves separate attention.

The malicious preinstall hook did not execute the payload in Node.js. It downloaded a standalone Bun runtime, and executed an obfuscated second stage under that — a detail documented in Snyk's teardown and Chainguard's analysis of the campaign.

Node was already there. The attacker chose to fetch a second interpreter anyway. That is a deliberate trade — extra network activity and a large binary download, in exchange for something worth more.

What the trade buys

It exits the instrumented process. Runtime protection for JavaScript builds is generally built around Node: NODE_OPTIONS preload hooks, require interception, and monitoring agents that instrument the Node process. A payload running under a different binary inherits none of that. Every hook the defender installed is attached to a runtime the malware is not using.

It breaks parent-child expectations. Detection rules for npm-based attacks tend to be written around npm spawning node spawning something suspicious. npm spawning sh spawning a downloaded ELF named bun does not match a rule written for the first shape, even though it is more anomalous.

The binary is not malicious. Bun is legitimate, signed, widely used, and downloaded from an ordinary distribution endpoint. Every reputation check on the file passes, because the file genuinely is what it claims to be. The malicious component is the script it runs, which arrives separately.

It normalises the network fetch. A build pipeline downloading a JavaScript runtime is unremarkable. Plenty of legitimate builds do exactly that. The fetch that bootstraps the attack looks like tooling setup.

It shrinks the payload. The stage-two script can be small and obfuscated because the runtime it needs is fetched on demand, rather than shipping capabilities inside the package where static analysis would see them.

Living off the land, updated for build pipelines

Endpoint security has understood "living off the land" for a decade: use PowerShell, certutil, or rundll32 rather than dropping a custom binary, because the tools already present are trusted.

Build pipelines invert the economics. A CI runner is ephemeral and network-connected by design, and downloading tools is its normal behaviour. So the equivalent technique is not to use what is already there — it is to fetch a legitimate tool and use that, because the fetch is indistinguishable from setup and the tool is genuinely trustworthy.

The same logic applies to any signed, popular, scriptable binary a build environment might plausibly download: alternative language runtimes, container tooling, cloud CLIs. The defensive implication is that "is this binary malicious" is the wrong question in a build environment. The binary is fine. The question is whether this pipeline had any business fetching and running it.

Detection that survives the technique

Signature and reputation approaches fail here by construction. What holds up:

Egress allowlisting. The technique has a hard dependency on an outbound fetch. A build environment permitted to reach only your registry, your artefact store, and your VCS cannot download a runtime. This breaks the chain at step one and is the highest-leverage control available.

Process-lineage anomalies rather than process names. Do not alert on "bun ran." Alert on "a process descended from a package install step executed a binary that was not present when the job started." The lineage is anomalous regardless of which binary it is, which means the rule survives the attacker switching to Deno, a static Python build, or anything else.

New-executable-in-workspace signals. An executable file appearing during dependency installation, then being executed, is a strong signal with a manageable false-positive rate — particularly if you already allowlist the handful of packages that legitimately compile native code.

Credential-path access from build steps. Whatever runtime executes it, the payload's objective was reading ~/.npmrc, ~/.aws, Vault tokens, SSH keys, and CI environment secrets. Access to those paths from a dependency-installation step is close to always wrong, and it is the one behaviour every variant of this campaign shares.

That last point is the durable one. Runtimes, packaging, and obfuscation are all cheap for an attacker to change. The objective is not. Detection anchored on credential access outlives detection anchored on tooling.

The uncomfortable part

Most organisations have far more visibility into a production container than into the CI job that built it. Production has runtime security, egress policy, and audit logging. The build pipeline has a YAML file and a job log that rotates in a fortnight.

That asymmetry is exactly backwards relative to the privilege involved. The build environment holds registry publish tokens, cloud deployment credentials, source code for every repository it touches, and signing keys. Attackers have been operating on this understanding for several years now — through Nx, Mastra, AsyncAPI's CI pipeline, and now keyv.

How Safeguard helps

Behavioural delta analysis on package versions. A caching library that newly declares a preinstall hook and newly fetches a binary from an external host has changed behaviour in a way no CVE will ever describe. Safeguard evaluates version-over-version behaviour, which is the only signal available before anyone has named the campaign.

Build-environment egress control through Lion. Lion enforces egress allowlists on build and agent environments, so the stage-one fetch fails and the stage-two exfiltration fails. It also brokers secrets just-in-time with capability scoping, so the credential objective is not sitting resident in the environment for a payload to read — and it produces signed audit trails that make "what did this job actually reach" a question with an answer.

Supply Chain Core inventory across every artefact type. Packages, containers, models, IDE extensions, and MCP servers land in one continuous CycloneDX and SPDX SBOM, with build-time records of what was installed where and when.

Eagle and Griffin for the aftermath. Eagle scopes which pipelines executed an affected version and which credentials were genuinely reachable from each. Griffin authors and tests the pinning and credential-migration changes across the affected repositories in parallel.

Look at your CI network policy. If a build job can reach an arbitrary host on the internet, this technique works against you today, and the next campaign will not need to invent anything new.

Sources: Snyk · Chainguard · Aikido · Socket

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.