Mini Shai-Hulud: SAP CAP and mbt npm Packages Backdoored via Bun-Loaded Credential Stealer with Claude Code Persistence

devsecops, ASPM, application security, vulnerability management, exposure management, reachability analysis, attack surface management, supply chain attack, npm malware, Mini Shai-Hulud, SAP CAP compromise, mbt npm, Bun runtime malware, Claude Code persistence, GitHub Actions credential theft, OIDC trusted publishing, npm worm, sandworm

On April 29, 2026, attackers published malicious versions of four npm packages in the SAP Cloud Application Programming Model (CAP) toolchain: mbt@1.2.48, @cap-js/sqlite@2.2.2, @cap-js/postgres@2.2.2, and @cap-js/db-service@2.10.1. Each compromised release adds a preinstall hook that downloads the Bun JavaScript runtime from GitHub Releases and then uses it to execute an obfuscated 11.6 MB credential-stealer. The campaign brands itself “Mini Shai-Hulud” through a hardcoded GitHub repository description that has now appeared on more than 1,197 victim accounts.

The campaign is technically distinct from the previous Shai-Hulud waves (September 2025, November 2025) in three ways. It uses Bun-as-runtime to bypass Node.js execution monitoring. It injects persistence into AI coding agent configuration files, including .claude/settings.json SessionStart hooks and .vscode/tasks.json folderOpen triggers. And it operates a peer-to-peer GitHub commit-search dead-drop that lets infected machines borrow tokens from other compromised hosts when they have no usable credentials of their own. The technical fingerprint also overlaps in five concrete ways with the TeamPCP campaigns Phoenix Security has covered since March 2026 (Trivy, Checkmarx, OpenVSX, LiteLLM): runner memory extraction via /proc/{pid}/mem, layered AES+RSA-4096 OAEP encryption with embedded public key, CIS-region locale exemption, AI coding agent targeting, and CI/CD credential harvesting at industrial scale.

The structural root cause for the cap-js packages is a misconfigured npm Trusted Publishing OIDC binding that trusted any workflow in cap-js/cds-dbs, not just the canonical release workflow on the main branch. A push to a non-main branch was sufficient to obtain a valid publish token. No CVE, GHSA, or OSV record had been assigned at the time of writing. Conventional CVE-driven vulnerability management would not flag any part of this incident.

TL;DR for Engineering Teams on Mini Sa1-hulud

What it is: Coordinated npm supply chain compromise of four SAP CAP and Cloud MTA Build Tool packages, delivering a Bun-loaded credential stealer with AI coding agent persistence. Attribution is consistent with the Shai-Hulud worm lineage, but the dead-drop description string is a new variant: “A Mini Shai-Hulud has Appeared.” No CVE assigned.

Where it bites: Any environment that ran npm install against mbt@1.2.48, @cap-js/sqlite@2.2.2, @cap-js/postgres@2.2.2, or @cap-js/db-service@2.10.1 on or after April 29, 2026 at 09:55 UTC. Transitive resolution counts: @cap-js/sqlite@2.2.2 declares @cap-js/db-service@^2.10.0, so a clean install of @cap-js/sqlite from a permissive range can pull the malicious db-service version without anyone listing it directly.

Why it matters: The payload reads /proc/{pid}/mem of the GitHub Actions Runner.Worker process to extract masked secrets directly from runner memory, sweeps 134 credential paths on developer machines, and queries cloud instance metadata services. Distinct from prior Shai-Hulud waves, this variant explicitly targets AI coding tool credentials and configuration files (~/.claude.json, MCP server configs, Kiro MCP config) for both harvesting and persistence. Stolen npm tokens are filtered for bypass_2fa: true and used to self-publish via direct HTTP PUT to the npm registry, bypassing the npm CLI and its standard telemetry.

Patch status: Three of four packages have clean post-incident successors published via SAP’s cap-npm OIDC trusted publisher. mbt@1.2.48 remains the latest dist-tag with no remediated version published. @cap-js/sqlite@2.2.2 was unpublished from npm; the other malicious versions carry deprecation strings. The cloudmtabot npm account that published all four malicious versions has been suspended.Immediate action: Search lockfiles for the four affected versions. If any environment has installed a compromised version, treat every credential reachable from that host as exposed and rotate. Audit GitHub for repositories with the description string “A Mini Shai-Hulud has Appeared” under your accounts, unexpected .claude/settings.json or .vscode/tasks.json files, commits authored by claude@users.noreply.github.com, and a typosquatted dependabout/… branch carrying a .github/workflows/format-check.yml file.

Update 30 April 2026 9am – 1200 Packages compromised: check Live tracker

Vulnerability Overview

FieldValue
VendorsSAP (mbt, Cloud MTA Build Tool); Cloud Application Programming community (@cap-js/*)
Productsmbt, @cap-js/db-service, @cap-js/sqlite, @cap-js/postgres
Vulnerability TypeSupply chain compromise; credential theft; npm self-propagating worm
CWECWE-829 (Inclusion of Functionality from Untrusted Control Sphere); CWE-506 (Embedded Malicious Code)
CVSSNot assigned
CVENot assigned
GHSA / OSVNot assigned at time of writing
Attack VectorNetwork (npm install execution; transitive resolution)
Active ExploitationConfirmed (1,197+ live victim repositories on GitHub)
AttributionShai-Hulud lineage (third campaign with this branding); operator unknown; CIS-region exemption present. Five-point TTP convergence with the TeamPCP campaigns Phoenix Security tracked across March 2026 (Trivy, Checkmarx, OpenVSX, LiteLLM). Convergence does not establish same-actor attribution.
Compromised npm accountcloudmtabot (suspended)
Exposure windowApril 29, 2026 09:55 UTC to ~14:00 UTC (publish window); mbt@1.2.48 remains resolvable as latest

Technical Anatomy of mini-sha1-hulud

devsecops, ASPM, application security, vulnerability management, exposure management, reachability analysis, attack surface management, supply chain attack, npm malware, Mini Shai-Hulud, SAP CAP compromise, mbt npm, Bun runtime malware, Claude Code persistence, GitHub Actions credential theft, OIDC trusted publishing, npm worm, sandworm

Root Cause: OIDC Trusted Publishing With Repo-Level Trust

For the three @cap-js/* packages, the structural root cause is documented in a first-party SAP statement filed in cap-js/cds-dbs Pull Request #1592 by SAP engineer patricebender at 14:02 UTC on the same day:

“On April 29, 2026, a supply chain attack compromised the repository — an unauthorized actor pushed malicious commits that hijacked the release workflow and triggered unauthorized npm publications. The attacker was able to publish compromised packages because the workflow had publish permissions without any manual approval gate.”

The mechanism: npm’s Trusted Publishing configuration for @cap-js/sqlite trusted any workflow in cap-js/cds-dbs, not the specific release workflow on the main branch. Trusted Publishing replaces long-lived npm tokens with short-lived OIDC tokens issued at workflow runtime, which is normally a security improvement. With repo-level trust, a push to a feature branch was enough to obtain a valid publish credential and ship a poisoned tarball to the public registry. PR #1592 fixes this by gating npm publish behind a GitHub Environment with manual approval.

The mbt@1.2.48 publish vector has not been confirmed publicly. All four malicious versions were published from the cloudmtabot npm account (the legitimate mbt maintainer); SAP’s clean post-incident versions at 13:46 UTC came from a separate cap-npm OIDC trusted publisher rather than from cloudmtabot. Maintainer-credential compromise is the recurring entry point for this class of incident, but the public evidence for mbt does not yet narrow the vector beyond that.

Live tracking of packages:

Main dashboardhttps://sha1hulud-phoenix.pplx.app/#/
Affected packageshttps://sha1hulud-phoenix.pplx.app/#/packages

See all previous articles: sha1-hulud coverage on Phoenix Security

Protect yourself with the latest intelligence on packages: https://phxintel.security/package.html

Exploit Path of mini-sha1-hulud

Step 1, Entry point. The attacker poisons four legitimate package tarballs without disturbing existing functionality. The legitimate package code (db.js, cds-plugin.js, type definitions) is preserved byte-for-byte against the prior clean release. The package.json adds a preinstall script and the tarball gains two new files: a 4.5 KB setup.mjs that is byte-identical across all four packages, and an execution.js weighing exactly 11,678,349 bytes whose hash differs per package. For mbt only, three new dependencies are also added: axios, tar, and unzip-stream.

Step 2, Vulnerability trigger. The npm preinstall lifecycle script runs node setup.mjs before any user-visible install output. setup.mjs detects the platform and architecture (including Alpine/musl on Linux), checks PATH for an existing bun binary, and if absent downloads Bun 1.3.13 from github.com/oven-sh/bun/releases/download/bun-v1.3.13/{asset}.zip. Routing the download through GitHub’s official release infrastructure looks like legitimate developer traffic to most network-level egress filters. The Bun binary is extracted to a temporary directory and used to execute execution.js.

Step 3, Execution impact. execution.js runs through two layers of obfuscation: an obfuscator.io string-table rotation with 48,370 entries decoded against a non-standard base64 alphabet, and a custom cipher StepSecurity dubbed ctf-scramble-v2 with a PBKDF2-derived master key. Both layers were fully recovered by static analysis. The decoded payload is JavaScript executing under Bun rather than Node.js. This is how the campaign avoids Node.js execution monitoring: defensive tooling looks at Node.js by default, while Bun is a Node-replacement runtime that downloads cleanly from a trusted URL, ships the same JavaScript surface area, and slips past most endpoint controls scoped to Node.

The runtime payload checks the system locale via JavaScript’s Intl API and POSIX environment variables (LC_ALL, LC_MESSAGES, LANGUAGE, LANG). If a Russian locale is detected, the payload logs “Exiting as russian language detected!” and terminates. The same CIS-region exemption appears across multiple Russian-speaking criminal operations and across both prior Shai-Hulud waves.

Protect yourself with the latest threat intelligence, get access to PHOENIX BLUE Today

Credential Harvesting (134 Path Patterns)

The payload sweeps developer machines and CI runners for credentials across all major categories. StepSecurity’s static deobfuscation recovered 134 distinct path and file patterns. The targets include:

CategoryTargets
GitHubPATs, OAuth grants, gh auth token output, GitHub Actions secrets
npm.npmrc tokens, automation tokens (filtered for bypass_2fa: true and org write scope)
AWS~/.aws/credentials, env vars, IMDS/IMDSv2 (169.254.169.254), ECS task metadata (169.254.170.2), IPv6 IMDS (fd00:ec2::254), STS identity, Secrets Manager values, SSM parameters
Azure~/.azure/, env vars, Key Vault names and secret values
GCP~/.config/gcloud/, application_default_credentials.json, Secret Manager values, project identity
Kubernetes~/.kube/config, in-pod service account tokens, kubeconfigs in /etc/, Helm config
AI tooling~/.claude.json, MCP server configs, Kiro MCP config (~/.kiro/settings/mcp.json), GCP token databases, Azure token caches
SSH and TLS~/.ssh/id_*, authorized_keys, known_hosts, /etc/ssh/ host keys, *.pem, *.key, *.p12, *.pfx, /etc/letsencrypt/
Password managers1Password (op), Bitwarden (bw), LastPass CLI
Git config~/.gitconfig, ~/.git-credentials
IaCTerraform Cloud credentials (~/.terraform.d/credentials.tfrc.json), terraform.tfvars, terraform.tfstate, Jenkinsfile, .gitlab-ci.yml, ansible.cfg
Messaging app sessionsSignal config, Slack cookies, Discord, Telegram, Element, Pidgin
VPN configsNordVPN, ProtonVPN, OpenVPN, FileZilla server lists
Crypto walletsBitcoin (wallet.dat), Ethereum keystores, Solana validator keypairs, Cardano signing keys, Monero, Litecoin, Dogecoin, Zcash, Dash, Ripple, Electrum, Exodus, Ledger Live, Atomic
Shell history.bash_history, .zsh_history, .mysql_history, .psql_history, .rediscli_history
System/etc/passwd, /etc/shadow, auth logs (accepted logins)

On Linux GitHub Actions runners, the payload spawns a Python child process that reads /proc/{pid}/mem of the Runner.Worker process and extracts masked secret structures from runner memory. This is the same TTP the TeamPCP threat actor used in the March 2026 Trivy and Checkmarx compromises. Two attribution-distinct campaigns now use it; defenders should treat runner memory extraction as a baseline expectation rather than a novel technique.

On Windows, the payload invokes PowerShell with -ExecutionPolicy Bypass. On non-CI hosts, it forks itself as a detached background process tagged with __DAEMONIZED=1 and the parent exits cleanly so npm install returns to the user with no visible error.

Encryption and Exfiltration of mini-sha1-hulud

Harvested data is serialised as JSON, gzip-compressed, encrypted with AES-256-GCM (32-byte key, 12-byte IV), and the AES key is wrapped using RSA-OAEP-SHA256 against an embedded RSA-4096 public key. The PEM is stored as gzip+base64 at file offset 9,429,992 in execution.js and decompressed at runtime via Bun.gunzipSync(). The encrypted bundle is committed as a JSON file to a public GitHub repository on the victim’s own account, structured as:

{“envelope”: “<base64 AES-256-GCM ciphertext>”, “key”: “<base64 RSA-4096 wrapped session key>”}

The key consequence for defenders: even with full access to the victim’s GitHub account, the dead-drop content is unreadable without the attacker’s RSA private key. There is no way to determine which specific credentials were exfiltrated. Rotation must be conservative and cover every credential reachable from the affected host.

Persistence Through AI Coding Agents

This is the most distinctive technical contribution of the campaign relative to prior Shai-Hulud waves. When the stolen GitHub token has write access to other repositories, the payload commits two persistence triggers into each one.

The first is .claude/settings.json containing a Claude Code SessionStart hook that re-executes the payload whenever a developer starts a Claude Code session against the repository. Anthropic issue claude-code #49778 raised this exact attack surface twelve days before the campaign and remains open without an Anthropic response.

The second is .vscode/tasks.json with a task using “runOn”: “folderOpen”, which executes when the project is opened in VS Code. Microsoft issue vscode #309406 raised this surface sixteen days earlier and was closed as By Design under the Workspace Trust model. The trust check does not cover commits made into already-trusted repositories, which is the vector this campaign exploits.

Both files are committed under the identity claude@users.noreply.github.com with the message “chore: update dependencies”, which can pass PR review as routine automation noise. A third persistence vector activates when the stolen token has workflow scope: the payload creates a typosquatted branch dependabout/github_actions/format/setup-formatter (note the missing t) and commits .github/workflows/format-check.yml impersonating the Dependabot service account. The injected workflow uses ${{ toJSON(secrets) }} to dump every repository secret into a build artifact named format-results.txt.

mini-sha1-huludSelf-Propagation via Direct Registry PUT

The harvested npm tokens fuel the worm component. The payload extracts tokens matching the regex /npm_[A-Za-z0-9]{36,}/g, validates each one against registry.npmjs.org/-/npm/v1/tokens filtering for bypass_2fa: true plus org-level write scope, enumerates accessible packages, patches setup.mjs and execution.js into a tarball copy, and publishes via a direct HTTP PUT to the npm registry without invoking the npm CLI. As of writing, no fifth package outside the original four has been observed in the wild, but the worm capability is functional code, not an inference.

A peer-to-peer fallback covers cases where the local victim has no usable token. The payload calls api.github.com/search/commits?q=OhNoWhatsGoingOnWithGitHub to find commits left by other compromised hosts, decodes base64 GitHub tokens from the matching commit messages, and tries them. A single GitHub user’s exfiltration repository can therefore correspond to multiple actual victims, and a victim’s credentials may end up exfiltrated through somebody else’s account.

TTP Convergence With the TeamPCP Lineage and mini-sha1-hulud

The Mini Shai-Hulud campaign is branded with the Shai-Hulud worm description string and inherits the dead-drop architecture of the September and November 2025 waves. The technical fingerprint, however, overlaps in five concrete ways with the TeamPCP campaigns Phoenix Security has tracked since March 2026 (the Trivy GitHub Actions compromise, the Checkmarx KICS and AST poisoning, the OpenVSX extension wave, and the LiteLLM PyPI backdoor).

1. /proc/{pid}/mem extraction of Runner.Worker. The Mini Shai-Hulud Python child process that reads runner memory is functionally identical to the credential-dumping component documented in TeamPCP’s Trivy entrypoint.sh (SHA-256 18a24f83…d1e5dd671a) and reused in the Checkmarx KICS setup.sh. Both target the same .NET process heap pattern ({“value”:”<secret>”,”isSecret”:true}). The technique is now demonstrably cross-actor; defenders should treat runner memory extraction as a baseline TTP rather than a TeamPCP signature.

2. Layered AES + RSA-4096 OAEP encryption with embedded public key. TeamPCP’s payloads (Trivy, Checkmarx, LiteLLM) wrap an AES-256-CBC session key with an embedded RSA-4096 OAEP public key and ship the encrypted bundle to a typosquat domain. Mini Shai-Hulud uses the same architecture with AES-256-GCM instead of CBC, with the public key stored as gzip+base64 PEM at offset 9,429,992 in execution.js. Both designs make the encrypted dead-drop unreadable without the attacker’s private key, regardless of defender access to the exfiltration channel.

3. CIS-region exemption via locale check. CybersecurityNews explicitly identifies the Russian-language locale exit as a recurring fingerprint across TeamPCP campaigns. Mini Shai-Hulud’s locale check (Intl API plus LC_ALL/LC_MESSAGES/LANGUAGE/LANG) terminates with the same outcome and the same operator-protective intent.

4. AI coding agent targeting. TeamPCP’s March 23, 2026 OpenVSX extensions (ast-results@2.53.0, cx-dev-assist@1.7.0) targeted Claude, Gemini, Copilot, Codex, and other agents with crafted prompts to coerce credential exfiltration. Mini Shai-Hulud targets the same surface from the other direction: harvesting ~/.claude.json and MCP server configs, and injecting .claude/settings.json SessionStart hooks for persistent re-execution. Different mechanisms, same target. Both campaigns treat the developer’s AI coding agent as part of the attack surface.

5. CI/CD-targeted credential harvesting at scale. Both campaigns sweep 50+ to 134 credential paths across SSH, cloud (AWS/GCP/Azure including IMDS queries), Kubernetes (in-pod service account tokens), Docker, Terraform, password manager CLIs, and crypto wallets. The path lists are not identical, but the architectural intent (maximum credential density per compromised host) and the prioritisation (npm/GitHub tokens for self-propagation, cloud credentials for blast radius) are convergent.

The convergence does not establish same-actor attribution. The Shai-Hulud branding lineage and TeamPCP’s typosquat domain operations are observable as separate operator infrastructure. What the convergence does show is that the TTPs Phoenix Security has flagged across the TeamPCP coverage (runner memory extraction, AI coding agent targeting, CI/CD credential harvesting at scale) are no longer specific to one operator. Multiple actors now use the same techniques, and defenders should plan accordingly.

For organizations that have run the TeamPCP detection playbook against their pipelines (the Trivy, Checkmarx, and LiteLLM IOC sweeps), the same operational muscles apply directly to Mini Shai-Hulud. The detections developed for one campaign carry over to the other.

Affected Versions

The campaign weaponized four foundational SAP-ecosystem npm packages. Combined weekly downloads across the four malicious versions: approximately 572,000.

PackageVulnerable VersionWeekly DownloadsSafe VersionNotes
mbt1.2.4852,0001.2.47npm wrapper for SAP’s Cloud MTA Build Tool. No clean successor published; 1.2.48 remains the latest dist-tag at the time of writing. Pin to 1.2.47 until SAP ships a remediated release.
@cap-js/db-service2.10.1260,0002.11.0Highest-volume target. Database service abstraction for the SAP Cloud Application Programming Model. Transitive risk: pulled by @cap-js/sqlite@2.2.2 via ^2.10.0, so a clean install of @cap-js/sqlite from a permissive range can land the malicious db-service version without anyone listing it directly.
@cap-js/sqlite2.2.2250,0002.4.0SQLite adapter for SAP CAP. Unpublished from npm shortly after detection. Pre-incident floor: 2.2.1.
@cap-js/postgres2.2.210,0002.3.0PostgreSQL adapter for SAP CAP. Pre-incident floor: 2.2.1.

A coordinated bump of @cap-js/hana@2.8.0 was also published alongside the post-incident releases. @cap-js/hana was not compromised; the bump is for ecosystem consistency rather than remediation.

All four malicious versions were published from the cloudmtabot npm account in a tight 2-hour 19-minute window on April 29, 2026 (09:55 to 12:14 UTC). The clean post-incident @cap-js/* versions at 13:46 UTC were published by SAP’s separate cap-npm GitHub Actions OIDC trusted publisher, not by cloudmtabot. The cloudmtabot account has since been suspended on npm.

devsecops, ASPM, application security, vulnerability management, exposure management, reachability analysis, attack surface management, supply chain attack, npm malware, Mini Shai-Hulud, SAP CAP compromise, mbt npm, Bun runtime malware, Claude Code persistence, GitHub Actions credential theft, OIDC trusted publishing, npm worm, sandworm

Phoenix Security Tracking Record

The four compromised packages surface in Phoenix Security’s vulnerability tracking system as new findings against the affected scopes. The tracking record format below mirrors the export schema used by Phoenix campaigns and remediation workflows:

DatePackageScopeNameVersionStatus
29-Apr@cap-js/db-service@cap-jsdb-service2.10.1NEW FINDING
29-Apr@cap-js/postgres@cap-jspostgres2.2.2NEW FINDING
29-Apr@cap-js/sqlite@cap-jssqlite2.2.2NEW FINDING
29-Aprmbt(top-level)mbt1.2.48NEW FINDING

The three @cap-js-scoped findings cluster cleanly under a single SAP CAP campaign view in Phoenix, with mbt tracked as a separate top-level finding because it sits outside the @cap-js namespace despite belonging to the same SAP development workflow. Organisations using Phoenix can group all four into a single remediation campaign with shared owners, while preserving the scope-level granularity needed for SBOM-driven dependency analysis.

Exposure Analysis

EnvironmentRisk LevelReason
CI/CD pipelines using affected packagesCritical/proc/{pid}/mem extraction reads the full readable address space of Runner.Worker. Every secret used in the workflow up to the install step is in scope, even if not directly referenced.
SAP enterprise developer machinesCriticalThese packages are typical for SAP BTP, Fiori, and S/4HANA extension development. Developer machines often carry production deployment credentials.
Self-hosted GitHub Actions runnersCriticalSame memory-read TTP applies. Self-hosted runners often share filesystems and credentials across jobs.
Cloud workloads with EC2/GCE/Azure metadata accessCriticalThe payload actively queries IMDS, IMDSv2 IPv6, and ECS task metadata. Any IAM role reachable from the host is in scope.
Developer machines with AI coding agents installedHighPersistent re-execution via Claude Code SessionStart hooks and VS Code folderOpen tasks survives across the developer session.
Repositories with permissive transitive dependency rangesHigh@cap-js/sqlite@2.2.2 resolves @cap-js/db-service@^2.10.0, so the malicious db-service version can land transitively.
Pipelines using –ignore-scripts or npm ci –ignore-scriptsNot affectedThe preinstall hook is the sole delivery mechanism. Ignoring scripts blocks the entire chain.

Real-World Impact of mini-sha1-hulud

Endor Labs frames the April 29 campaign as a deliberate pivot in the Shai-Hulud lineage: away from the broad-spectrum, hundreds-of-packages waves of 2025, toward a tight enterprise-targeted compromise of the SAP developer ecosystem. The four affected packages are foundational to SAP Cloud Application Programming Model and Cloud MTA workflows, both of which run on developer machines and CI runners that typically hold credentials for production SAP Business Technology Platform deployments. The package count is smaller; the credential value per victim is much higher.

Within hours of the initial publish, public GitHub search showed more than 1,197 repositories carrying the description string “A Mini Shai-Hulud has Appeared.” Snyk’s direct GitHub API count was 1,076 at 15:17 UTC; by the time later observers checked, the figure had grown. Each repository is a developer machine or CI runner that ran npm install during the exposure window.

The victim repositories follow a consistent pattern. They are created on April 29, 2026 between 10:00 and 15:00 UTC. They carry randomized two-word names drawn from the Dune universe (kanly-sietch-78, sardaukar-melange-550, ghola-ornithopter-356, and similar combinations of Atreides, Harkonnen, Fremen, Gesserit, Fedaykin, Sardaukar, Tleilaxu, Kralizec, Mentat) followed by a 1-3 digit number. Each contains only a README.md in the rendered view; the encrypted exfiltration files in results/results-<unix-ms>-<counter>.json are present in the Git history but may not appear in the GitHub UI after partial cleanup.

The repositories are spread across multiple compromised developer accounts, including but not limited to BGEEL, virinchy48, Shrenath1903, shrivathsa11, gruposbftechrecruiter, and nikra89. These accounts are themselves victims; their stolen GitHub tokens were used to auto-create the exfiltration repositories under their own identities. The first observed victim repository, by GitHub API timestamp, appeared on gruposbftechrecruiter at 10:01:07 UTC, less than six minutes after mbt@1.2.48 was published.

The campaign is the third in the Shai-Hulud lineage. Between September 2025 and November 2025, the worm infected more than 1,300 unique npm packages across its 1.0 and 2.0 variants, with a combined download volume in the hundreds of millions per month. The blast radius is amplified by the worm’s design: each compromised maintainer’s npm token is used to publish poisoned versions of every other package that the maintainer has rights to, capped at 100 packages per victim.

The September 14-16, 2025 wave (Shai-Hulud 1.0) compromised over 500 npm packages, with ngx-bootstrap (version 18.1.4, approximately 300,000 weekly downloads) identified by ReversingLabs as the likely patient zero. The most prominent compromised packages included @ctrl/tinycolor at 2.2 million weekly downloads and ng2-file-upload at approximately 100,000 weekly downloads. The 1.0 wave used a Node.js-based monolithic bundle.js payload and a postinstall lifecycle hook.

The November 21-26, 2025 wave (Shai-Hulud 2.0, branding string “Sha1-Hulud: The Second Coming.”) was significantly larger. Datadog’s tracking identified 1,092 unique backdoored package versions across at least 796 unique packages with a combined volume of 130 million monthly downloads. The patient zero is believed to be @asyncapi/specs at 1.4 million weekly downloads, with the worm cascading through corporate namespaces including Zapier, Postman, PostHog, ENS Domains (Ethereum Name Service), Browserbase, and the AsyncAPI organisation itself (36 distinct packages trojanised). The 2.0 wave shifted to a preinstall lifecycle hook and adopted the Bun runtime as a Node.js detection bypass, the same evasion choice the April 2026 Mini variant inherits. Wiz tracked over 25,000 attacker-created exfiltration repositories across roughly 350 GitHub users at a peak rate of 1,000 new repositories every 30 minutes.

The April 29, 2026 Mini Shai-Hulud campaign reuses the worm branding (the dead-drop description string) while introducing three new technical components: the OIDC trusted-publishing entry point on a misconfigured release workflow, AI coding agent persistence through Claude Code SessionStart hooks and VS Code tasks.json folderOpen triggers, and a peer-to-peer GitHub commit-search dead-drop for token sharing across infected hosts. The full list of npm packages compromised in the April 2026 wave has not yet been publicly cataloged. Researchers recommend running active scanners rather than relying on static package lists, since the worm’s self-propagation means downstream packages are added hourly as the campaign continues.

Detection Guidance

Indicators of Compromise

TypeIndicator
Dead-drop repo descriptionA Mini Shai-Hulud has Appeared
Dead-drop repo naming regex(sardaukar\|mentat\|fremen\|atreides\|harkonnen\|gesserit\|prescient\|fedaykin\|tleilaxu\|siridar\|kanly\|sayyadina\|ghola\|powindah\|prana\|kralizec)-(sandworm\|ornithopter\|heighliner\|stillsuit\|lasgun\|sietch\|melange\|thumper\|navigator\|fedaykin\|futar\|slig\|phibian\|laza\|cogitor\|ghola)-\d{1,3}
P2P commit dead-drop stringOhNoWhatsGoingOnWithGitHub
Cipher saltctf-scramble-v2
Daemonisation env var__DAEMONIZED
Lockfile markertmp.987654321.lock
Author signatureclaude@users.noreply.github.com with commit message chore: update dependencies
Workflow injection branchdependabout/github_actions/format/setup-formatter
Injected workflow file.github/workflows/format-check.yml (uses toJSON(secrets), exfils via format-results.txt artifact)
Compromised npm accountcloudmtabot (suspended)
Bun download URLgithub.com/oven-sh/bun/releases/download/bun-v1.3.13/bun-{platform}.zip
Cloud metadata reads169.254.169.254, 169.254.170.2, [fd00:ec2::254]
setup.mjs SHA-256 (all packages)4066781fa830224c8bbcc3aa005a396657f9c8f9016f9a64ad44a9d7f5f45e34
execution.js SHA-256 (mbt@1.2.48)80a3d2877813968ef847ae73b5eeeb70b9435254e74d7f07d8cf4057f0a710ac
execution.js SHA-256 (@cap-js/sqlite@2.2.2)6f933d00b7d05678eb43c90963a80b8947c4ae6830182f89df31da9f568fea95
Embedded /proc/mem dumper SHA-25629ac906c8bd801dfe1cb39596197df49f80fff2270b3e7fbab52278c24e4f1a7
mbt@1.2.48 tarball shasum0af7415d65753f6aede8c9c0f39be478666b9c12
@cap-js/db-service@2.10.1 tarball shasum4b04304f6d51392e3f43856c94ca95800518a694
@cap-js/sqlite@2.2.2 tarball shasum7b6a28e92149637e5d7c7f4a2d3e54acd507c929
@cap-js/postgres@2.2.2 tarball shasume80824a19f48d778a746571bb15279b5679fd61c

Cross-Wave Payload Hashes (Shai-Hulud Lineage)

Defenders running detection across CI runners and developer machines benefit from checking for the prior-wave payload hashes alongside the Mini Shai-Hulud IOCs above. The Phoenix scanner and the wider community detection tools all match against these hashes directly, so unmodified payloads from earlier waves are still detectable if any infected dependency lingers in your tree.

WavePayload FileSHA-256
Shai-Hulud 1.0 (Sept 2025)bundle.js46faab8ab153fae6e80e7cca38eab363075bb524edd79e42269217a083628f09
Shai-Hulud 2.0 (Nov 2025)setup_bun.jsa3894003ad1d293ba96d77881ccd2071446dc3f65f434669b49b3da92421901a
Shai-Hulud 2.0 (Nov 2025)bun_environment.jsf099c5d9ec417d4445a0328ac0ada9cde79fc37410914103ae9c609cbc0ee068
Shai-Hulud 2.0 (Nov 2025)bun_environment.js (variant)62ee164b9b306250c1172583f138c9614139264f889fa99614903c12755468d0
Mini Shai-Hulud (Apr 2026)setup.mjs4066781fa830224c8bbcc3aa005a396657f9c8f9016f9a64ad44a9d7f5f45e34
Mini Shai-Hulud (Apr 2026)execution.js (mbt)80a3d2877813968ef847ae73b5eeeb70b9435254e74d7f07d8cf4057f0a710ac
Mini Shai-Hulud (Apr 2026)execution.js (@cap-js/sqlite)6f933d00b7d05678eb43c90963a80b8947c4ae6830182f89df31da9f568fea95

The 1.0 payload was a monolithic Node.js bundle.js. The 2.0 wave switched to two-stage execution under the Bun runtime, with setup_bun.js as the bootstrapper and bun_environment.js as the obfuscated 480,000-line credential stealer. The Mini variant retains the two-stage Bun pattern while renaming the files to setup.mjs and execution.js. The structural similarity between 2.0 and the Mini variant is what allows existing 2.0 detection rules (including the Microsoft Defender KQL queries from m4nbat/100_days_of_kql_2026 Day 17) to fire on the new campaign without modification.

Log Indicators

Primary detection signal for the Mini variant: an unexpected download of bun-v1.3.13 from github.com/oven-sh/bun/releases during an npm install step. SAP development pipelines and developer machines that have never legitimately used the Bun runtime should never see this download. A single hit on this URL during install-time is sufficient to treat the host as compromised pending further investigation. Endor Labs identifies this as the fastest, lowest-false-positive indicator for SAP teams to check first.

CI build logs that show node setup.mjs followed by a Bun release download from github.com/oven-sh/bun during an npm install step are a strong primary signal. Process-tree telemetry showing node spawning bun and bun spawning python (the /proc/mem dumper child) on a Linux runner is a high-confidence detection on its own. Outbound HTTPS connections from runners to api.github.com/user/repos (dead-drop creation) and api.github.com/search/commits?q=OhNoWhatsGoingOnWithGitHub (P2P token search) during install steps should never occur in legitimate workflows.

Scanner Coverage

Snyk has published advisories for all four affected versions (SNYK-JS-MBT-16321404, SNYK-JS-CAPJSDBSERVICE-16321402, SNYK-JS-CAPJSSQLITE-16321405, SNYK-JS-CAPJSPOSTGRES-16321403). Aikido, Socket, and StepSecurity have published IOC feeds. Phoenix Security correlates these advisories with runtime workload data to identify reachable execution rather than declared dependency state.

For active in-tree detection, the Phoenix Security npm compromise scanner at Security-Phoenix-demo/Shai-Hulud-Sha1-Hulud-V2-npm-compromise-scanner checks node_modules and the wider repository file tree against the cross-wave payload hashes listed above and against the IOC strings (A Mini Shai-Hulud has Appeared, OhNoWhatsGoingOnWithGitHub, ctf-scramble-v2). It is the recommended starting point for organizations that need a fast verdict on whether any tree under their control contains a known malicious payload.

For ad-hoc verification, npx @safedep/vet scan provides a one-command check against SafeDep’s malicious-package database and is useful for developer machines where running a full scanner is impractical. Datadog also maintains an open repository tracking all 1,092 unique backdoored package versions linked to the 2.0 wave.

Microsoft Defender KQL queries from m4nbat/100_days_of_kql_2026 (Day 17) catch the Bun + TruffleHog + /proc/mem chain that this campaign reuses; they were authored for SHA1-Hulud and apply to Mini Shai-Hulud unmodified.

Verification Steps

  1. Search lockfiles: rg -n ‘”mbt”|”@cap-js/db-service”|”@cap-js/sqlite”|”@cap-js/postgres”‘ package-lock.json npm-shrinkwrap.json yarn.lock pnpm-lock.yaml.
  2. Run the Phoenix Security npm compromise scanner across affected repositories: git clone https://github.com/Security-Phoenix-demo/Shai-Hulud-Sha1-Hulud-V2-npm-compromise-scanner and execute against your node_modules and project file tree. The scanner checks the cross-wave payload hashes and IOC strings in a single pass.
  3. For ad-hoc developer-machine checks, run npx @safedep/vet scan against any project that has recently installed dependencies.
  4. Check transitive resolution: npm ls @cap-js/db-service to identify pulls via @cap-js/sqlite@2.2.2.
  5. Sweep your GitHub organizations for repositories matching the Dune naming regex with the “Mini Shai-Hulud” description string.
  6. Search org-wide for commits containing OhNoWhatsGoingOnWithGitHub and for the typosquatted dependabout/… branch.
  7. Audit pull requests for .claude/settings.json and .vscode/tasks.json additions authored under the claude@users.noreply.github.com identity.
  8. Review CI build logs for any node setup.mjs or Bun release download during the April 29 exposure window.
  9. Check developer machines for .claude/settings.json containing a SessionStart hook and .vscode/tasks.json with runOn: folderOpen.

Remediation Guidance

Immediate Actions

  1. Pin to clean versions: @cap-js/db-service@2.11.0, @cap-js/sqlite@2.4.0, @cap-js/postgres@2.3.0, mbt@1.2.47 (no remediated mbt successor exists).
  2. If any environment has installed a compromised version, treat every credential reachable from that host as exposed. Rotate npm tokens first (highest blast radius via worm propagation), then GitHub PATs, AWS/Azure/GCP credentials, Kubernetes kubeconfigs, Docker configs, Terraform Cloud credentials, SSH keys, password manager CLI tokens, and any AI tooling tokens stored in ~/.claude.json or MCP server configs.
  3. Block outbound traffic from CI runners to api.github.com/user/repos POST and api.github.com/search/commits queries unless explicitly required by the workflow.
  4. Sweep all GitHub organizations for the IOCs listed above and remove any injected .claude/settings.json, .vscode/tasks.json, or dependabout/… branches before they re-trigger on developer session start.
  5. Revoke OIDC publish trust for cap-js/cds-dbs if you maintain a forked publishing infrastructure, until workflow-scoped trust with manual approval is in place.

Temporary Mitigations

For organizations that cannot patch immediately or want broader hardening across the npm ecosystem:

  • Default CI to npm install –ignore-scripts and explicitly allow lifecycle scripts only for packages that genuinely require them. This neutralizes the entire class of pre-install-driven credential theft, which has been the delivery mechanism for the original Shai-Hulud, SHA1-Hulud, the Bitwarden CLI compromise, and Mini Shai-Hulud.
  • Use pnpm v10 or Bun-as-installer, both of which block lifecycle scripts by default unless explicitly allowed.
  • Configure GitHub Actions runners with IMDSv2 and a hop limit of 1 so containerized builds cannot reach instance metadata.
  • Enforce dependency cooldowns of 24-72 hours for non-critical updates. Public detection of supply chain attacks typically occurs within hours; a short hold provides a meaningful detection window.

Long-Term Hardening

OIDC trusted publishing is a security improvement over long-lived tokens, but only when the trust binding is workflow-scoped and branch-protected. Audit every npm Trusted Publishing configuration for repo-level (rather than workflow-level) trust. Gate every npm publish workflow behind a GitHub Environment with a manual approval gate, modeled on cap-js/cds-dbs PR #1592.

Treat AI coding agent configuration files as part of the supply chain attack surface. .claude/settings.json, MCP server configs, and .vscode/tasks.json should be reviewed in PR diffs with the same scrutiny applied to .github/workflows/.

Phoenix Security Recommendations

The Mini Shai-Hulud campaign is another data point in the structural failure of CVE-driven vulnerability management. Four packages, 570,000 weekly downloads, more than 1,197 confirmed victim repositories within hours of publication, and zero CVE, GHSA, or OSV records assigned at the time of writing. Workflows that wait for an NVD entry before flagging a component will miss this entirely.

Attack surface management: Phoenix identifies which environments and pipelines reference the four affected packages, with explicit handling of transitive resolution. Organizations that pull @cap-js/sqlite from a permissive range can pull the malicious @cap-js/db-service@2.10.1 without anyone listing it directly; Phoenix surfaces these transitive paths against installed-state data.

Contextual deduplication: SAP CAP packages are typically deployed across many development repositories within a single enterprise. Phoenix correlates findings into a single prioritized backlog rather than producing duplicate alerts per repository.

Reachability analysis: Phoenix distinguishes environments where the malicious version was installed from those where the install actually executed during the exposure window. An environment that installed the package on April 30 from a registry that already returned the unpublished or deprecated version has a different exposure profile than a CI pipeline that ran a successful npm install between 09:55 and 14:00 UTC on April 29.

Remediation campaigns: Phoenix campaigns track SHA pinning across affected workflows, secret rotation completion, persistence cleanup (.claude/settings.json, .vscode/tasks.json, dependabout/… branches), and post-rotation validation. Each campaign maps to an owning team for coordinated response across SAP development organizations that may have hundreds of affected pipelines.

Ownership attribution: When SAP CAP is deployed across multiple application teams, knowing which team owns each affected pipeline is the difference between a structured rotation and chaos. Phoenix maps vulnerable components to responsible teams automatically.

The structural argument for ASPM holds across this campaign as it did for TeamPCP, Trivy, and LiteLLM: the security tools and the developer toolchain are themselves now part of the attack surface, and traditional scanner-based workflows cannot reach what they cannot see.

References

  • Phoenix Security — TeamPCP Backdoors LiteLLM: PyPI Supply Chain Attack (related Phoenix coverage; precedent for AES+RSA encryption architecture and Kubernetes lateral movement)
  • StepSecurity — A Mini Shai-Hulud has Appeared: Obfuscated Bun Runtime Payloads Hit SAP-Related npm Packages (April 29, 2026)
  • Snyk — “A Mini Shai-Hulud Has Appeared”: Bun-Based Stealer Hits SAP @cap-js and mbt npm Packages
  • Aikido Security — Mini Shai-Hulud Targets SAP npm Packages With a Bun-Based Secret Stealer
  • Socket Security — SAP CAP npm Packages Targeted in Shai-Hulud Supply Chain Attack
  • Wiz Research — Shai-Hulud 2.0: Ongoing Supply Chain Attack Analysis
  • SafeDep — Mini Shai-Hulud and SAP Compromise
  • The Hacker News — SAP npm Packages Compromised by “Mini Shai-Hulud” Credential-Stealing Malware
  • Onapsis — Emerging Supply Chain Attack (“Mini Shai-Hulud”) Targeting SAP CAP Ecosystem
  • cap-js/cds-dbs Pull Request #1592 — Workflow approval gate (SAP first-party root cause statement)
  • cap-js/cds-dbs Issue #1588 — StepSecurity disclosure
  • SAP/cloud-mta-build-tool Issue #1224 — StepSecurity disclosure
  • SAP/open-ux-tools Issue #4616 — Independent third disclosure by longieirl
  • anthropics/claude-code Issue #49778 — SessionStart hook attack surface (filed 12 days pre-campaign)
  • microsoft/vscode Issue #309406 — tasks.json runOn: folderOpen attack surface (filed 16 days pre-campaign)
  • CISA — Widespread Supply Chain Compromise Impacting npm Ecosystem (Shai-Hulud lineage advisory)
  • Palo Alto Unit 42 — “Shai-Hulud” Worm Compromises npm Ecosystem in Supply Chain Attack
  • Palo Alto Unit 42 — Shai-Hulud 2.0 Renewed npm Compromise Analysis
  • Cirosec — A Collection of Shai-Hulud 2.0 IOCs (cross-wave payload hashes)
  • Securelist (Kaspersky) — Shai-Hulud Worm Infects 500 npm Packages in a Supply Chain Attack
  • Securelist (Kaspersky) — Shai-Hulud 2.0 Technical Analysis
  • ReversingLabs — Shai-Hulud Supply Chain Attack Spreads Token-Stealing Malware on npm (patient zero analysis)
  • Endor Labs — Mini Shai-Hulud npm Worm Hits SAP Developer Packages (primary source for SAP-targeted framing and Bun runtime evasion analysis)
  • Endor Labs — Shai-Hulud 2 Malware Campaign Targets GitHub and Cloud Credentials Using Bun Runtime (lineage context)
  • Datadog Security Labs — The Shai-Hulud 2.0 npm Worm: Analysis (1,092 unique backdoored package versions tracker)
  • SecurityWeek — 640 npm Packages Infected in New Shai-Hulud Supply Chain Attack
  • Sysdig — Return of the Shai-Hulud Worm Affects Over 25,000 GitHub Repositories
  • Security Online — Shai-Hulud Supply Chain Attack Now Targets CrowdStrike’s npm Packages
  • Security-Phoenix-demo/Shai-Hulud-Sha1-Hulud-V2-npm-compromise-scanner — Phoenix Security cross-wave npm compromise scanner with hash-based and IOC-string detection
  • SafeDep vet — npx @safedep/vet scan for ad-hoc malicious-package detection
  • m4nbat/100_days_of_kql_2026 (Day 17) — Microsoft Defender KQL queries for Bun + TruffleHog + /proc/mem chain detection
  • CybersecurityNews — SAP npm Packages Compromised to Harvest Developer and CI/CD Secrets (source for the TeamPCP-fingerprint Russian-locale-exit observation)
  • Phoenix Security — TeamPCP’s Five-Day Siege: Trivy, Checkmarx, OpenVSX, and npm (related Phoenix coverage; TTP precedent for runner memory extraction and AI-agent targeting)

The results are clear:

  • Bazaarvoice saved $6.3M in developer time and for teams removed critical in the first weeks of adoption
  • ClearBank cut critical container vulnerabilities by 96–99% and reclaimed 4 hours per engineer per week.
  • IAS saved an equivalent of 1.5M in development hours and reduced SCA-to-container noise by 82.4%
  • Optimizely has been able to act on vulnerabilities sitting on the backlog.

👉 Book a demo today

Or learn how Phoenix Security slashed millions in wasted dev time for fintech, retail, and adtech leaders.

Fix with remediaiton don’t chase ghost vulnerabilities

Francesco is an internationally renowned public speaker, with multiple interviews in high-profile publications (eg. Forbes), and an author of numerous books and articles, who utilises his platform to evangelize the importance of Cloud security and cutting-edge technologies on a global scale.

Discuss this blog with our community on Slack

Join our AppSec Phoenix community on Slack to discuss this blog and other news with our professional security team

From our Blog

Between 21:57 and 23:30 UTC on April 22, 2026, a malicious @bitwarden/cli@2026.4.0 was live on npm for 93 minutes — long enough to reach CI/CD pipelines, developer workstations, and cloud automation hosts. The payload steals credentials across GitHub, AWS, GCP, and Azure, propagates as a self-replicating npm worm, injects GitHub Actions workflow stealers, and poisons AI coding assistants by injecting an invisible manifesto into shell configuration files. This is the first documented npm supply chain attack executed through Trusted Publishing.
Francesco Cipollone
Phoenix Security launched Phoenix Blue at VulnCon 2026 — a standalone agentic vulnerability intelligence platform at phxintel.security. The platform indexes 300K+ CVE records and 2,080,512 advisory references from 15+ sources, adds six proprietary scoring systems, zero-day pre-CVE detection, and malicious package monitoring. Free for everyone, built agent-first with REST, GraphQL, and MCP integration.
Francesco Cipollone
Phoenix ships workflow automation, a rebuilt Remedies screen, container deduplication, and Azure connectors — so security teams spend less time managing findings and more time closing them.
Rowan Scott
Contents
Derek

Derek Fisher

Head of product security at a global fintech

Derek Fisher – Head of product security at a global fintech. Speaker, instructor, and author in application security.

Derek is an award winning author of a children’s book series in cybersecurity as well as the author of “The Application Security Handbook.” He is a university instructor at Temple University where he teaches software development security to undergraduate and graduate students. He is a speaker on topics in the cybersecurity space and has led teams, large and small, at organizations in the healthcare and financial industries. He has built and matured information security teams as well as implemented organizational information security strategies to reduce the organizations risk.

Derek got his start in the hardware engineering space where he learned about designing circuits and building assemblies for commercial and military applications. He later pursued a computer science degree in order to advance a career in software development. This is where Derek was introduced to cybersecurity and soon caught the bug. He found a mentor to help him grow in cybersecurity and then pursued a graduate degree in the subject.

Since then Derek has worked in the product security space as an architect and leader. He has led teams to deliver more secure software in organizations from multiple industries. His focus has been to raise the security awareness of the engineering organization while maintaining a practice of secure code development, delivery, and operations.

In his role, Jeevan handles a range of tasks, from architecting security solutions to collaborating with Engineering Leadership to address security vulnerabilities at scale and embed security into the fabric of the organization.

Jeevan Singh

Jeevan Singh

Founder of Manicode Security

Jeevan Singh is the Director of Security Engineering at Rippling, with a background spanning various Engineering and Security leadership roles over the course of his career. He’s dedicated to the integration of security practices into software development, working to create a security-aware culture within organizations and imparting security best practices to the team.
In his role, Jeevan handles a range of tasks, from architecting security solutions to collaborating with Engineering Leadership to address security vulnerabilities at scale and embed security into the fabric of the organization.

James

James Berthoty

Founder of Latio Tech

James Berthoty has over ten years of experience across product and security domains. He founded Latio Tech to help companies find the right security tools for their needs without vendor bias.

christophe

Christophe Parisel

Senior Cloud Security Architect

Senior Cloud Security Architect

Chris

Chris Romeo

Co-Founder
Security Journey

Chris Romeo is a leading voice and thinker in application security, threat modeling, and security champions and the CEO of Devici and General Partner at Kerr Ventures. Chris hosts the award-winning “Application Security Podcast,” “The Security Table,” and “The Threat Modeling Podcast” and is a highly rated industry speaker and trainer, featured at the RSA Conference, the AppSec Village @ DefCon, OWASP Global AppSec, ISC2 Security Congress, InfoSec World and All Day DevOps. Chris founded Security Journey, a security education company, leading to an exit in 2022. Chris was the Chief Security Advocate at Cisco, spreading security knowledge through education and champion programs. Chris has twenty-six years of security experience, holding positions across the gamut, including application security, security engineering, incident response, and various Executive roles. Chris holds the CISSP and CSSLP certifications.

jim

Jim Manico

Founder of Manicode Security

Jim Manico is the founder of Manicode Security, where he trains software developers on secure coding and security engineering. Jim is also the founder of Brakeman Security, Inc. and an investor/advisor for Signal Sciences. He is the author of Iron-Clad Java: Building Secure Web Applications (McGraw-Hill), a frequent speaker on secure software practices, and a member of the JavaOne Rockstar speaker community. Jim is also a volunteer for and former board member of the OWASP foundation.

Join our Mailing list!

Get all the latest news, exclusive deals, and feature updates.

The IKIGAI concept
x  Powerful Protection for WordPress, from Shield Security PRO
This Site Is Protected By
Shield Security PRO