By falco365 · Published April 30, 2026

The Bun runtime is becoming the malware delivery vehicle of 2026

Two supply-chain compromises in 48 hours both fetch Bun and run an obfuscated credential stealer. Lightning PyPI and four SAP CAP npm packages, both Team PCP.

The Bun runtime is becoming the malware delivery vehicle of 2026
Analysis

In a 48-hour window between April 29 and April 30, 2026, two unrelated-looking supply-chain compromises landed on different package ecosystems with the same novel runtime evasion: both fetch the Bun JavaScript runtime from GitHub at install time, and both use it to execute an 11-MB obfuscated credential stealer. The npm compromise is four SAP Cloud Application Programming Model packages first reported by Aikido under the name "Mini Shai-Hulud." The PyPI compromise is the popular lightning package, first reported by Socket. A group calling itself Team PCP claimed responsibility for the PyPI side through a Tor onion site linked from a GitHub issue. The shared TTP — Bun as the second-stage runtime — is the headline. Defenders' static analysis tooling is built for Node.js and Python; Bun is neither.

What we know

The npm compromise affected four packages with malicious versions published April 29, 2026:

  • @cap-js/sqlite v2.2.2
  • @cap-js/postgres v2.2.2
  • @cap-js/db-service v2.10.1
  • mbt v1.2.48

The PyPI compromise affected lightning versions 2.6.2 and 2.6.3 on April 30, 2026. Socket reports the package receives several hundred thousand downloads per day from Python machine-learning environments. Version 2.6.1, published January 30, 2026, is reported clean.

The npm payload chain: a preinstall hook in package.json runs node setup.mjs, which detects OS and architecture, downloads Bun v1.3.13 from GitHub releases, and uses Bun to execute an 11.7-MB obfuscated execution.js. The PyPI payload chain is structurally identical: a start.py bootstrapper added to the package detects host architecture, fetches Bun, and launches a hidden _runtime/router_runtime.js daemon with suppressed output.

The credential-harvest scope is broad — every secret reachable from a developer or CI environment:

  • GitHub tokens including gh auth token output and Actions tokens.
  • npm publish tokens from .npmrc.
  • GitHub Actions secrets, extracted by an embedded Python helper that reads /proc memory of the Runner.Worker process.
  • Cloud credentials across AWS STS / Secrets Manager / SSM, Azure subscriptions / Key Vault, GCP project identity / Secret Manager.
  • Kubernetes service account tokens.
  • Claude and MCP configuration files, Azure token caches, GCP token databases, Signal configuration, Electrum wallets, VPN configuration.

Exfiltration on the npm side uses GitHub itself as the transport. The malware creates public repositories with randomized names and the description A Mini Shai-Hulud has Appeared, then writes AES-256-GCM encrypted result files (with RSA-wrapped keys) under results/results-<timestamp>-<counter>.json. A propagation channel uses a GitHub commit dead-drop: the malware searches commits for the string OhNoWhatsGoingOnWithGitHub, decodes matching commit messages as base64-encoded GitHub tokens, and uses them to access additional repositories.

The dead-drop pattern is novel. Searching public GitHub commits for a magic string lets the operator distribute new tokens without a fixed C2 domain — every git push by anyone, anywhere, becomes potential infrastructure.
Why Bun matters

Picking Bun as the second-stage runtime is the most interesting technical choice. It accomplishes several things simultaneously:

  • Static analysis evasion. Most npm-ecosystem static-analysis tooling expects Node.js semantics. Bun has different module resolution, different runtime APIs in some cases, and many sandboxes don't model it correctly. PyPI-ecosystem tooling expects Python; running JavaScript via Bun from a Python package is even further off the analysis path.
  • No interpreter dependency on the victim. Bun is a single static binary. The malware doesn't need a Node.js or Python runtime that fits its expectations — it brings its own.
  • Faster than Node for execution. An 11-MB obfuscated bundle that has to deobfuscate, run a string-scrambling layer, and execute hundreds of credential-collection routines wants the runtime startup overhead to be small enough to complete during npm install without obvious delay. Bun's startup is faster than Node.

The obfuscation layer in the npm sample is labeled ctf-scramble-v2. The payload exits on Russian locale settings, daemonizes itself on non-CI machines for persistent harvesting, and detects CI to alter its behavior accordingly.

Worm-style propagation through GitHub Actions

Beyond credential theft, the npm payload includes a worm component. When it detects a GitHub Actions release workflow for cap-js/cds-dbs, it can modify package tarballs to inject itself, increment the patch version, and repack the tarball — propagating to whoever installs the next release. It also pushes files into repositories under .vscode/ and .claude/ paths using commit messages titled chore: update dependencies authored by claude <claude@users.noreply.github.com>. The choice of impersonating Claude commits is opportunistic: any reviewer who sees a Claude-authored commit may dismiss it as agent-generated maintenance.

Targeting
  • Software developers using SAP CAP — anyone whose package.json resolved to the affected versions of @cap-js/sqlite, @cap-js/postgres, @cap-js/db-service, or mbt in the April 29 window.
  • Python ML developers using lightning — versions 2.6.2 and 2.6.3 from April 30 onward, until pinned to 2.6.1 or to a maintainer-confirmed clean release.
  • CI/CD runners running npm install or pip install against either ecosystem during the affected windows. Embedded /proc memory dumping of Runner.Worker means GitHub Actions secrets are explicitly in scope.
  • Developer workstations with broad cloud-credential access — AWS, Azure, GCP CLI configurations, Kubernetes contexts, SSH keys.
TTPs and infrastructure
  • Initial access — package version takeover (npm + PyPI). The reported vector for the PyPI compromise is consistent with credentials previously stolen from earlier supply-chain incidents, used to publish.
  • Execution — preinstall lifecycle hook (npm) or import-time bootstrapper (PyPI) that fetches Bun and runs the second stage.
  • Persistence — daemonization on non-CI hosts; immediate exit on CI to maximize secret collection without leaving forensic timestamps.
  • Defense evasion — Bun runtime to bypass Node/Python-focused analysis; ctf-scramble-v2 string obfuscation; Russian-locale exit.
  • Command and control — GitHub itself, via attacker-created public repositories with the Mini Shai-Hulud signature description and AES-256-GCM encrypted result files.
  • Lateral movement — GitHub commit dead-drop using the magic string OhNoWhatsGoingOnWithGitHub to discover new tokens; tarball injection in detected GitHub Actions release workflows.
Indicators of compromise

Affected packages and versions:

  • @cap-js/sqlite 2.2.2
  • @cap-js/postgres 2.2.2
  • @cap-js/db-service 2.10.1
  • mbt 1.2.48
  • lightning 2.6.2 and 2.6.3

SHA-256 hashes (from @cap-js/sqlite@2.2.2):

  • setup.mjs4066781fa830224c8bbcc3aa005a396657f9c8f9016f9a64ad44a9d7f5f45e34
  • execution.js6f933d00b7d05678eb43c90963a80b8947c4ae6830182f89df31da9f568fea95

Filesystem and behavioral artifacts:

  • Package contains setup.mjs + execution.js (npm) or start.py + _runtime/router_runtime.js (PyPI).
  • Bun v1.3.13 download from GitHub releases at install time (egress to github.com/oven-sh/bun/releases from a CI runner that doesn't normally pull Bun).
  • Public GitHub repositories created with description A Mini Shai-Hulud has Appeared under the victim's account.
  • Commits authored by claude <claude@users.noreply.github.com> with subject chore: update dependencies touching .vscode/ or .claude/ paths.
  • GitHub commit messages containing the literal string OhNoWhatsGoingOnWithGitHub.
Detection and mitigation
  • Pin to known-clean versions immediately. lightning 2.6.1; for the SAP CAP packages, the immediately prior versions per maintainer guidance.
  • Audit lockfiles across every active repository. Any resolution to the listed versions during the disclosure window means the install ran the payload.
  • Treat any developer or CI host that ran the affected versions as fully compromised. Rotate GitHub tokens, npm publish tokens, AWS / Azure / GCP credentials, Kubernetes service account tokens, SSH keys, and any secret reachable from the host's environment. The malware enumerates broadly; assume everything reachable is exfiltrated.
  • Search GitHub audit logs for repository creation by your service accounts with descriptions matching Mini Shai-Hulud, and for commits authored under claude@users.noreply.github.com that you didn't make.
  • Detect Bun fetches on hosts that have no business running Bun. Outbound egress to github.com/oven-sh/bun/releases from a CI runner mid-install is a strong signal.
  • Block preinstall and postinstall by default in CI via npm ci --ignore-scripts. Allowlist scripts that genuinely need to run.
Attribution discipline

The PyPI compromise is claimed by a group self-identifying as Team PCP on a Tor onion site linked from a GitHub issue on the Lightning project. Socket reports tooling overlap with Shai-Hulud and Mini Shai-Hulud npm campaigns. Claimed Team PCP connections to LAPSUS$ are unverified.

For tracking purposes we use the campaign name Mini Shai-Hulud (Aikido's term for the npm cluster) and treat Team PCP as a self-applied label, not a confirmed actor identity. Tool-overlap-based attribution to a single operator group is consistent with the public reporting but should not be promoted to confident attribution without further evidence.

What this signals

Bun-as-malware-runtime is the durable takeaway. Defenders' static-analysis pipelines are still organized around Node.js for the npm ecosystem and Python for PyPI. A second-stage payload running under a third runtime evades the lane-specific tooling on either side. Expect more of this pattern. Detection engineering should add Bun-egress monitoring (and Deno, and WASM-based runtimes generally) as a category — not because Bun is itself malicious, but because its appearance during package installation in environments that don't legitimately use it is now a strong adversary signal. The Lightning + SAP cluster is the first time this TTP has appeared in two distinct ecosystems within 48 hours; it won't be the last.

This compromise sits in the same npm-supply-chain pattern documented in CVE-2026-12091 — postinstall lifecycle hooks running attacker-controlled code at every install — but with a more sophisticated runtime-evasion layer on top. The structural defense is identical: --ignore-scripts by default, sandboxed install boundaries, capability-narrowed CI tokens. Pattern-by-pattern patching of individual incidents loses to the structural fix.

One last note on the threat-intelligence shape. As of publication, the Mini Shai-Hulud cluster has no observable presence in commodity criminal markets — no broker pricing, no exploit-kit packaging, no forum trade volume. That tracks with how this kind of bug class actually monetizes: the operator IS the toolchain author, distributing through legitimate package registries directly rather than selling through .onion forums. The defensive lesson is the same one we made earlier for the AI-IDE marketplace surface — when the attacker can publish to npm or PyPI under a plausible name, dark-web monitoring is the wrong instrument. Marketplace-side telemetry, lockfile diffs, and CI install instrumentation are.

Update, May 4, 2026: The April 29 packages were the worm's first propagation step, not its conclusion. OIDC tokens stolen from the mbt and @cap-js/sqlite pipelines were used to publish intercom-client@7.0.4 the following day — ~2M weekly downloads, private-repo exfiltration, expanded multi-cloud credential sweep. Full analysis of the Shai-Hulud propagation loop.