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/sqlitev2.2.2@cap-js/postgresv2.2.2@cap-js/db-servicev2.10.1mbtv1.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 tokenoutput and Actions tokens. - npm publish tokens from
.npmrc. - GitHub Actions secrets, extracted by an embedded Python helper that reads
/procmemory of theRunner.Workerprocess. - 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 installwithout 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.jsonresolved to the affected versions of@cap-js/sqlite,@cap-js/postgres,@cap-js/db-service, ormbtin 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 installorpip installagainst either ecosystem during the affected windows. Embedded/procmemory dumping ofRunner.Workermeans 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-v2string 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
OhNoWhatsGoingOnWithGitHubto discover new tokens; tarball injection in detected GitHub Actions release workflows.
Indicators of compromise
Affected packages and versions:
@cap-js/sqlite2.2.2@cap-js/postgres2.2.2@cap-js/db-service2.10.1mbt1.2.48lightning2.6.2 and 2.6.3
SHA-256 hashes (from @cap-js/sqlite@2.2.2):
setup.mjs—4066781fa830224c8bbcc3aa005a396657f9c8f9016f9a64ad44a9d7f5f45e34execution.js—6f933d00b7d05678eb43c90963a80b8947c4ae6830182f89df31da9f568fea95
Filesystem and behavioral artifacts:
- Package contains
setup.mjs+execution.js(npm) orstart.py+_runtime/router_runtime.js(PyPI). - Bun v1.3.13 download from GitHub releases at install time (egress to
github.com/oven-sh/bun/releasesfrom a CI runner that doesn't normally pull Bun). - Public GitHub repositories created with description
A Mini Shai-Hulud has Appearedunder the victim's account. - Commits authored by
claude <claude@users.noreply.github.com>with subjectchore: update dependenciestouching.vscode/or.claude/paths. - GitHub commit messages containing the literal string
OhNoWhatsGoingOnWithGitHub.
Detection and mitigation
- Pin to known-clean versions immediately.
lightning2.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 underclaude@users.noreply.github.comthat you didn't make. - Detect Bun fetches on hosts that have no business running Bun. Outbound egress to
github.com/oven-sh/bun/releasesfrom a CI runner mid-install is a strong signal. - Block
preinstallandpostinstallby default in CI vianpm 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.