Skip to content

Back to the catalog

Why NPM Malware Keeps Reaching for Bun | Supply Chain Security | Blog | Endor Labs
endorlabs.comarticle

Why NPM Malware Keeps Reaching for Bun | Supply Chain Security | Blog | Endor Labs

Endor Labs analyzes why a string of npm supply-chain campaigns — Shai-Hulud 2.0 (Nov 2025, 796 packages backdoored) and an April 2026 SAP-ecosystem attack on mbt, @cap-js/db-service, @cap-js/sqlite and @cap-js/postgres — all use the same second stage: a preinstall script that downloads the Bun JavaScript runtime to run an obfuscated credential stealer. Bun is attractive to attackers because it's a userland, statically-linked binary with a different process name than node, bypasses Node's --require/NODE_OPTIONS instrumentation hooks, and ships built-in shell/decompression/HTTP primitives (Bun.$, Bun.gunzipSync) that avoid the suspicious imports scanners look for. The piece also notes CVE-2026-24910, a trusted-dependency spoofing flaw in Bun's package manager, and recommends prioritized controls: disable npm lifecycle scripts (ignore-scripts=true) with an auditable allowlist, enforce a minimum release age/cooldown on dependencies, block known-malicious versions pre-install, eliminate long-lived npm/cloud tokens, and detect on process lineage rather than binary name.

TL;DR npm malware campaigns (Shai-Hulud 2.0, an April 2026 SAP-ecosystem attack) keep abusing preinstall scripts to fetch the Bun runtime for stealthier credential theft, and Endor Labs lays out layered controls — ignore-scripts, release-age cooldowns, and process-lineage detection — to stop it.
Document

What it is

An Endor Labs analysis of a recurring npm supply-chain technique: compromised packages add a preinstall hook that downloads the Bun JavaScript runtime and uses it to host a credential stealer. Bun is stage two; stage one is that npm install executes arbitrary code before printing its first line of output. Bun itself is a Zig-written runtime built on JavaScriptCore (not V8), shipped as a single statically-linked binary, and is now owned by Anthropic.

How it works

The Shai-Hulud 2.0 worm (24 Nov 2025) dropped two files — setup_bun.js and bun_environment.js — into legitimate packages and added a preinstall script to run them; it hit 796 packages across 1,092 versions, ~20M weekly downloads. The April 2026 SAP-ecosystem campaign fetched Bun via a preinstall hook to run an 11.6 MB obfuscated stealer. Bun is chosen because it installs entirely in userland (curl -fsSL https://bun.sh/install | bash drops a binary in ~/.bun/bin — no root, no admin ticket) and is batteries-included: Bun.$ gives shell execution, Bun.spawnSync handles processes, Bun.gunzipSync handles decompression, and fetch is native — everything a stealer needs. It also defeats EDR that watches for node processes during install and attaches through hooks Bun doesn't honor.

Affected packages (April 2026 campaign)

mbt, @cap-js/db-service, @cap-js/sqlite, @cap-js/postgres.

What to do

Do not block bun.sh at the proxy — engineers have legitimate reasons for Bun (Stripe, Notion, Linear, Replit all run it; 2–4x faster CI, TS with no build step, faster serverless cold starts). Instead cut the install-time mechanism. Beyond the summary's five controls, two concrete specifics:

  • Bun's own package manager blocks dependency lifecycle scripts by default; permitting one requires a trustedDependencies entry or bun pm trust <pkg>. Treat this as the posture to replicate for npm (an auditable allowlist).
  • For detection, write analytics against process lineage — at least one vendor has published an analytic for nothing more specific than a Bun process spawned by npm. The two dropped filenames above are usable IOCs.

Caveats

Bun's safer defaults are not perfect: CVE-2026-24910 is a trusted-dependency spoofing flaw in Bun. The detection signature "Bun spawned by npm" will also fire on any legitimate such invocation, so it needs environment-specific tuning rather than blanket blocking.

CVEs named here

  • CVE-2026-24910

Technologies named here

Techniques named here

Threat actors named here