Mini Shai-Hulud Malware Hits SAP npm [2026 Deep Dive]
Bottom Line
This was not a routine malicious package upload. Mini Shai-Hulud turned trusted SAP ecosystem packages into an install-time secret stealer with worm-like propagation, so any affected install should be treated as a full credential exposure event.
Key Takeaways
- ›Four SAP-related npm releases were confirmed compromised on April 29, 2026: mbt 1.2.48 and three @cap-js packages
- ›The injected path was a new preinstall hook that launched setup.mjs, downloaded Bun 1.3.13, and ran execution.js
- ›Researchers observed developer and CI/CD secret theft across GitHub, npm, AWS, Azure, GCP, and Kubernetes targets
- ›The malicious versions were live for hours, not days, but install-time execution means brief exposure still carries high impact
- ›Removing the package is not enough; teams should assume token theft, rotate secrets, and audit GitHub activity immediately
On April 29, 2026, a supply-chain campaign nicknamed Mini Shai-Hulud hit the SAP JavaScript ecosystem by trojanizing trusted npm packages rather than publishing obvious lookalikes. The result was an install-time compromise path: developers and CI runners pulling the affected versions could execute a Bun-backed credential stealer before application code ever ran. What makes this incident important is not just the malware family lineage, but how efficiently it weaponized ordinary dependency installation inside SAP CAP and Cloud MTA workflows.
- Researchers confirmed four compromised versions: mbt@1.2.48, @cap-js/sqlite@2.2.2, @cap-js/postgres@2.2.2, and @cap-js/db-service@2.10.1.
- The injected logic added a preinstall hook that launched setup.mjs and then execution.js.
- The loader fetched Bun v1.3.13 and used it to run an obfuscated payload outside the package’s expected behavior.
- Observed targets included GitHub, npm, cloud credentials, Kubernetes tokens, and CI/CD secrets.
- Because execution happened during install, a short exposure window still created high-severity compromise risk.
CVE Summary Card
- Incident type: npm supply-chain compromise targeting SAP ecosystem packages
- CVE status: No public CVE assignment was visible as of April 29, 2026
- Affected packages: mbt@1.2.48, @cap-js/sqlite@2.2.2, @cap-js/postgres@2.2.2, @cap-js/db-service@2.10.1
- Execution point: npm install via a malicious preinstall lifecycle script
- Primary behavior: Bun bootstrap, secret harvesting, GitHub-based exfiltration, and propagation logic
- High-risk environments: developer laptops, CI runners, build agents, and any host with registry or cloud credentials
- First response: identify installs, isolate impacted hosts, rotate secrets, and review GitHub activity
Bottom Line
Mini Shai-Hulud turned trusted SAP npm packages into an install-time execution channel. If an affected version ran on a workstation or CI runner, treat it as a likely credential theft incident rather than a simple dependency hygiene problem.
Vulnerable Code Anatomy
The small change that created a large blast radius
The core trick was brutally simple: the malicious releases inserted a new preinstall path into otherwise familiar packages. That matters because lifecycle hooks execute during dependency resolution, before a developer has any reason to suspect that the package has become active malware.
{
"scripts": {
"preinstall": "node setup.mjs"
}
}From a review perspective, this is exactly the sort of delta teams miss when they trust a previously safe package name. The package still looks legitimate, still installs, and in some cases still delivers the expected CLI or library behavior. The dangerous part is the new execution path, not a broken user-facing feature.
Stage 1: the loader
Researchers reported that setup.mjs was byte-identical across the compromised packages. Its job was to bootstrap execution, not to do the heavy stealing itself.
- It detected platform details such as architecture and libc flavor.
- It downloaded the appropriate Bun v1.3.13 binary from GitHub Releases.
- It extracted the archive, marked the binary executable, and launched execution.js.
- On Windows, Socket reported use of -ExecutionPolicy Bypass, which raises the risk of silent execution in developer environments.
This design is instructive. The attacker avoided depending on the host’s normal Node.js monitoring assumptions by bringing its own runtime. That reduces friction, improves portability, and complicates naive detections focused only on expected package files.
Stage 2: the obfuscated payload
The second stage was a large obfuscated JavaScript payload, roughly 11.6 MB to 11.7 MB depending on the package variant. Reporting from Socket and Wiz describes multiple capabilities that elevate this beyond commodity package malware.
- Secret harvesting from developer machines, including
~/.npmrc, Git credentials, SSH material, Docker config, and shell history. - Cloud and cluster targeting across AWS, Azure, GCP, and Kubernetes.
- GitHub token theft, including cached CLI access via gh auth token.
- CI-aware behavior, including memory scraping on runners to recover masked secrets.
- GitHub-based exfiltration using attacker-created repositories on the victim’s own account.
- Propagation logic intended to republish malicious changes using stolen npm access.
There was also a regional guardrail: the payload reportedly exited when locale signals suggested a Russian-language environment. That kind of check is not defensive noise. It is operational tradecraft, and it matches prior TeamPCP-linked behavior noted by Wiz and Socket.
Attack Timeline
The timeline on April 29, 2026 is a reminder that modern supply-chain incidents can unfold in hours, not release cycles. Based on public reporting from Onapsis, Socket, StepSecurity, Wiz, and Snyk, the sequence looked like this:
- 09:55:25 UTC: mbt@1.2.48 was published.
- 10:03:09 UTC: Socket’s early detection window for the mbt release appears in public reporting.
- 11:25:47 UTC: @cap-js/sqlite@2.2.2 was published.
- 11:33:06 UTC: detection of the malicious @cap-js/sqlite version was reported.
- 12:14:00 UTC: @cap-js/postgres@2.2.2 and @cap-js/db-service@2.10.1 were published.
- 12:20:37 UTC: those CAP package releases were reported detected.
- 13:33:00 UTC: the compromised @cap-js versions were reported superseded by clean releases.
- 15:40:00 UTC: mbt was reported superseded.
- 17:45 UTC: Wiz published an update strengthening attribution toward TeamPCP.
The most important operational lesson is not the exact minute stamps. It is that the exposure window was long enough for real installs, and install-time malware does not need persistence on the registry to create lasting compromise. Once the package runs, the problem moves from package management into identity, CI, and cloud response.
Exploitation Walkthrough
Conceptually, the attack path was straightforward and effective because it piggybacked on normal engineering behavior.
- A developer or CI job resolved one of the affected versions, directly or transitively.
- During npm install, the new preinstall hook executed automatically.
- setup.mjs fetched or located a Bun runtime and launched execution.js.
- The payload fingerprinted the environment to distinguish developer endpoints from CI runners.
- It harvested credentials from files, environment variables, cloud metadata services, and GitHub tooling.
- It encrypted the collected data and exfiltrated it through GitHub repositories created with the victim’s own access.
- If viable tokens were present, it attempted to spread by modifying additional packages or repositories.
- On some developer environments, it planted IDE- and assistant-focused persistence artifacts such as
.claude/settings.jsonand.vscode/tasks.json.
That sequence explains why this incident matters beyond SAP developers alone. The malware was not targeting a runtime bug in CAP. It was targeting the trust boundary around package installation, local secrets, automation identities, and repository write permissions.
It also explains why simple questions like whether the app still built successfully are irrelevant. In this class of incident, a successful build can be evidence that the malware had everything it needed.
Hardening Guide
Immediate response for potentially exposed teams
- Search lockfiles, build logs, caches, and artifact stores for mbt@1.2.48, @cap-js/sqlite@2.2.2, @cap-js/postgres@2.2.2, and @cap-js/db-service@2.10.1.
- Isolate hosts or runners that installed those versions before beginning cleanup.
- Rotate GitHub, npm, cloud, Kubernetes, SSH, and CI/CD credentials that were reachable from the affected environment.
- Review GitHub for unexpected repositories, branches, commits, workflows, or new automation behavior.
- Inspect for files such as
setup.mjs,execution.js,.claude/settings.json, and.vscode/tasks.json.
Build pipeline controls that actually help
- Default CI to npm ci --ignore-scripts where lifecycle scripts are not explicitly required.
- Separate build identities from publish identities so a compromised build host cannot republish packages.
- Use short-lived, narrowly scoped tokens instead of long-lived broad registry or repo credentials.
- Block direct egress from package-installation steps except to approved registries and artifact mirrors.
- Alert on package installers spawning unexpected runtimes such as bun, python, or PowerShell.
Dependency and release governance
- Diff package manifests and lifecycle hooks between releases, not just application source files.
- Pin internal builds to vetted versions instead of floating to the newest patch release automatically.
- Require provenance, protected release workflows, and strong separation between source commits and package publication.
- Continuously inventory which packages are allowed to execute install scripts.
- Sanitize logs and incident attachments before sharing them externally; if engineers need to scrub cloud keys or tokens quickly, a utility such as the Data Masking Tool is practical for response coordination.
package.json can be more dangerous than a large diff in application source.Architectural Lessons
1. Package names are not trust anchors
The affected artifacts were not obvious typosquats. They were trusted package names in a business-critical ecosystem. That means allowlists based only on package identity are too weak when the package’s execution behavior can change between releases.
2. Install time is a production-grade attack surface
Engineering teams still mentally downgrade npm install as a setup step instead of a code-execution boundary. Mini Shai-Hulud exploited that gap. If your build path permits arbitrary lifecycle scripts with broad outbound network access and reusable credentials, the attacker already has a strong foothold.
3. Developer environments are part of cloud security
This incident crossed local endpoints, GitHub, registries, cloud APIs, and CI memory. The old model of treating workstation security, SaaS identity, and cloud posture as separate programs is increasingly brittle. The same install event can touch all three.
4. Identity scope matters more than cleanup speed
Fast supersession of malicious versions helped reduce future installs, but it did not erase already-stolen tokens. The decisive control is limiting what any single developer or runner credential can publish, read, or modify.
5. AI and IDE integrations are now part of the threat model
Public reporting tied this campaign to persistence and tooling paths that referenced local assistant and editor settings. Whether or not a given organization uses those exact tools, the lesson is general: developer convenience integrations are privileged automation surfaces and should be reviewed like any other credentialed agent.
Mini Shai-Hulud is best understood as a supply-chain identity incident delivered through npm. The package compromise was the opening move. The real objective was control over the secrets and automation layers that modern SAP development depends on.
Frequently Asked Questions
Was Mini Shai-Hulud assigned a CVE? +
Which SAP npm packages were affected by Mini Shai-Hulud? +
If I uninstall the bad package, am I safe? +
Why did this attack use Bun instead of just Node.js? +
How should CI pipelines be hardened against this class of npm attack? +
npm ci --ignore-scripts in tightly controlled jobs. Then reduce token scope, restrict network egress during installs, and alert when package managers spawn unexpected binaries or reach cloud metadata services.Get Engineering Deep-Dives in Your Inbox
Weekly breakdowns of architecture, security, and developer tooling — no fluff.