Skip links
Picture of Vahagn Vardanian

Vahagn Vardanian

Co-founder and CTO of RedRays

SAP npm Packages Hijacked to Steal Cloud Credentials and Weaponize AI Coding Agents

On 29 April 2026, four official npm packages from the SAP JavaScript and cloud application development ecosystem were compromised in a coordinated supply chain attack dubbed "mini Shai-Hulud". The poisoned releases - published between 09:55 and 12:14 UTC - embed a Bun-based credential stealer that harvests developer secrets, GitHub and npm tokens, GitHub Actions secrets, AWS / Azure / GCP / Kubernetes credentials and browser-stored passwords, then exfiltrates them to public repositories created on the victim's own GitHub account. The campaign - attributed by Wiz with high confidence to the TeamPCP operators behind the original Shai-Hulud, Checkmarx and Bitwarden compromises - also introduces a first-of-its-kind persistence vector that abuses AI coding agent configurations (Claude Code SessionStart hook and VS Code tasks.json folderOpen trigger) to re-execute on any developer workstation that opens an infected repository.

Affected Packages
4
Primary Attack Components
2
Attack Capabilities & TTPs
4
Operational Tradecraft
4
Hunting & Hardening Notes
2

Executive Summary

  • Compromised Packages: @cap-js/[email protected], @cap-js/[email protected], @cap-js/[email protected], [email protected] - all published on 29 April 2026 between 09:55 and 12:14 UTC.
  • Bun-Based Credential Stealer: Malicious preinstall hook in package.json downloads a platform-specific Bun runtime from GitHub Releases, then executes an 11.6 MB execution.js stealer + propagation framework.
  • AI Agent Persistence (First-of-Its-Kind): The payload commits .claude/settings.json abusing the Claude Code SessionStart hook and .vscode/tasks.json with "runOn": "folderOpen" into every accessible repo - opening an infected project in Claude Code or VS Code re-triggers the malware.
  • Self-Propagation: Stolen GitHub / npm tokens are used to inject malicious GitHub Actions workflows and republish poisoned versions to the npm registry.
  • Root Cause: Compromised maintainer account (RoshniNaveenaS) plus a permissive npm OIDC trusted-publisher configuration that trusted any workflow on any branch in cap-js/cds-dbs, not only the canonical release-please.yml on main.
  • Scope of Damage: 1100+ public GitHub repositories with the description "A Mini Shai-Hulud has Appeared" have been observed receiving exfiltrated, AES-256-GCM + RSA-4096 encrypted secrets.

Primary Attack Components

Malicious preinstall hook deploys Bun-based credential stealer

CRITICAL ATT&CK T1195.002 / T1059 @cap-js/* + mbt Supply Chain / Execution
Chain: npm install → preinstall → setup.mjs → Bun runtime → execution.js (11.6 MB stealer)

The compromised releases add a new preinstall script to package.json that runs setup.mjs, a runtime bootstrapper which downloads a platform-specific Bun ZIP from GitHub Releases, extracts it and immediately executes the Bun binary against execution.js. The payload harvests local developer credentials, GitHub and npm tokens, GitHub Actions secrets, cloud secrets from AWS / Azure / GCP / Kubernetes, and - new in this operation - passwords stored in Chrome, Safari, Edge, Brave and Chromium. Exfiltration is encrypted with AES-256-GCM and the symmetric key is wrapped with a TeamPCP-linked RSA-4096 public key, making the stolen data decryptable only by the attacker. Any workstation or CI/CD agent that ran npm install against the affected versions must be considered compromised.

Wiz Threat Intelligence Report - purge node_modules + lock files, rotate every credential touched by an affected machine, audit cloud audit logs for unfamiliar API calls.

AI coding agent configuration weaponized for persistence (Claude Code + VS Code)

CRITICAL ATT&CK T1546 / T1195.002 .claude/settings.json + .vscode/tasks.json Persistence (Novel)
Trigger: Claude Code SessionStart hook + VS Code "runOn":"folderOpen" task

The payload commits itself into every accessible GitHub repository by writing two files: .claude/settings.json - abusing Claude Code's SessionStart hook to execute the stealer whenever a session is started in the repo - and .vscode/tasks.json - declaring a task with "runOn": "folderOpen" that automatically launches the malware as soon as the folder is opened in Microsoft Visual Studio Code. Per StepSecurity, this is one of the first supply chain attacks to deliberately target AI-agent configuration files as a persistence and propagation vector. Any developer who clones an infected repository and opens it in Claude Code or VS Code is silently re-infected, even if the original poisoned npm package has already been removed.

StepSecurity Advisory - grep all repos for .claude/settings.json with a SessionStart hook and for .vscode/tasks.json entries with "runOn":"folderOpen"; revert and force-push clean history.

Attack Capabilities & TTPs

Initial access - permissive npm OIDC trusted-publisher configuration enabled the package takeover

HIGH ATT&CK T1199 / T1078.004 cap-js/cds-dbs (GitHub Actions) Initial Access
Root cause: trusted publisher accepted any workflow on any branch (not pinned to release-please.yml @ main)

After compromising maintainer RoshniNaveenaS's GitHub account, the attacker pushed a modified workflow to a non-main branch and used it to exchange a short-lived npm OIDC token, which was then printed in CI logs and used to publish the three @cap-js/* packages without provenance. The critical configuration gap: npm's OIDC trusted publisher for @cap-js/sqlite trusted any workflow in cap-js/cds-dbs with id-token: write permission and the environment: npm reference - not only the canonical release-please.yml on main. The mbt package is suspected to have been published using a stolen static npm token belonging to the cloudmtabot service account.

npm Trusted Publishers Documentation - pin every trusted publisher to a specific workflow file path and to main only; prefer environments that require manual approval for publish.

Cloud and CI/CD secret harvesting (AWS, Azure, GCP, Kubernetes, GitHub Actions)

HIGH ATT&CK T1552.001 / T1528 execution.js Credential Access
Targets: ~/.aws, ~/.azure, ~/.config/gcloud, kubeconfig, GitHub Actions runner secrets

The 11.6 MB Bun-executed payload enumerates the standard credential locations for the four major cloud SDKs and Kubernetes, plus environment variables and runner secrets exposed inside GitHub Actions jobs. On infected build agents this gives the attacker a path from a single npm dependency to the customer's production cloud accounts - a classic supply chain blast-radius amplifier.

Aikido Security Analysis - rotate all cloud access keys, GitHub Actions secrets and kubeconfig tokens used on machines that resolved the affected versions.

Browser-stored password theft (Chrome, Safari, Edge, Brave, Chromium)

HIGH ATT&CK T1555.003 Local browser stores Credential Access
New TeamPCP capability - not present in prior Shai-Hulud / Checkmarx / Bitwarden waves

The SAP operation introduces a browser password stealer that targets Chrome, Safari, Edge, Brave and Chromium-based browsers. According to Wiz, this capability is new for TeamPCP and was not seen in prior operations. Any saved password on an infected developer workstation - corporate SSO fallbacks, personal accounts, banking, social - must be considered exposed and reset.

BleepingComputer Coverage - force browser password reset and re-login on every infected workstation; review SSO sign-in logs.

Self-propagation via injected GitHub Actions workflows and npm republishing

HIGH ATT&CK T1098 / T1554 .github/workflows + npm Lateral Movement / Worm
Path: stolen GH/npm tokens → inject CI workflow → harvest repo secrets → publish poisoned npm versions

Using stolen GitHub and npm tokens, the malware injects a malicious GitHub Actions workflow into the victim's repositories to siphon repository-level secrets, and republishes poisoned versions of the victim's own npm packages to the registry - turning every infected developer into a downstream distribution node and giving the campaign worm-like reach across the open-source ecosystem.

Snyk Threat Brief - audit GitHub Actions workflow history for unauthorized commits and revoke any PAT or OIDC token issued from those runs.

Operational Tradecraft

GitHub-based C2: encrypted exfiltration to victim-owned public repos

MEDIUM ATT&CK T1567 / T1102 github.com (victim accounts) C2 / Exfiltration
IOC: public repo description "A Mini Shai-Hulud has Appeared" - 1100+ observed

Stolen secrets are AES-256-GCM encrypted, the symmetric key wrapped under an embedded RSA-4096 public key, then pushed to a newly created public GitHub repository on the victim's own account with the description "A Mini Shai-Hulud has Appeared." In prior TeamPCP operations this was a fallback channel; in mini Shai-Hulud it is the primary C2 - and effectively impossible to block without breaking developer access to GitHub.

GitHub Search IOC - alert your developers to check their own GitHub accounts for any unexpected public repository matching this description and report it.

Maintainer account compromise - RoshniNaveenaS and cloudmtabot

MEDIUM ATT&CK T1078 / T1528 npm + GitHub maintainer accounts Account Takeover
Entry: GitHub account takeover for @cap-js/*; static npm token theft for mbt

The three @cap-js/* packages were published after attackers gained control of maintainer RoshniNaveenaS's GitHub account and abused the OIDC trusted publisher misconfiguration. The mbt publication is attributed to a compromised static npm token belonging to the cloudmtabot service account, with the original token-leak channel still under investigation.

npm 2FA Guidance - enforce hardware-backed 2FA on every publishing account, retire static npm tokens in favour of OIDC tied to a single workflow path.

Russian-locale geo-fence skips infection on RU systems

MEDIUM ATT&CK T1497.001 execution.js locale check Defense Evasion
Behaviour also seen in prior Checkmarx and Bitwarden TeamPCP operations

The payload exits early on systems whose locale is Russian. Wiz tracks the same check across the Checkmarx and Bitwarden compromises, reinforcing the TeamPCP attribution and giving defenders a strong behavioural signature for sandbox detonation rules.

Wiz Attribution Notes - informational only; do not rely on locale spoofing as a defensive control.

Patched maintainer releases supersede the compromised versions

INFO REMEDIATION @cap-js/* + mbt Safe Versions
Pin to safe versions and rebuild lockfiles from clean state

The maintainers have published clean versions superseding the compromised releases: @cap-js/sqlite v2.4.0 (or v2.3.0); @cap-js/postgres v2.3.0; @cap-js/hana v2.8.0 / v2.7.2; mbt v1.2.49. The published guidance for @cap-js/db-service reuses the v2.10.1 number - verify against the current npm page and the maintainer changelog before pinning. The team also migrated to npm OIDC trusted publishing in November 2025 - the residual risk lay in the trust-policy scope, not in OIDC itself.

npm @cap-js/sqlite - pin to a patched version, delete node_modules and lockfiles, and reinstall from a clean cache.

Hunting & Hardening Notes

PowerShell -ExecutionPolicy Bypass on Windows installers

LOW ATT&CK T1059.001 setup.mjs (Windows path) Defense Evasion
Hunt: PowerShell child processes spawned from npm/Node with -ExecutionPolicy Bypass

On Windows hosts the bootstrapper invokes PowerShell with -ExecutionPolicy Bypass, providing both an EDR hunting opportunity and a hardening lesson - block or alert on PowerShell child processes spawned from Node / npm with that flag.

PowerShell Execution Policies - add a Sysmon / EDR rule for powershell.exe -ExecutionPolicy Bypass originating from node.exe or npm.cmd.

Unvalidated HTTP redirect handling in the bootstrap loader

LOW CWE-601 / CWE-494 setup.mjs download path Insecure Network
setup.mjs follows HTTP redirects without validating the destination host

The bootstrapper follows HTTP redirects without validating the destination, so even partial control over a CDN or DNS path along the redirect chain would let an attacker redirect the Bun download to an arbitrary binary. While this is the attacker's own loader, the same pattern is regularly observed in legitimate supply chain tooling - block egress to non-allow-listed redirect targets and pin Bun (or any runtime) by SHA-256 in CI.

OWASP Unvalidated Redirects - pin runtime downloads by digest and restrict CI egress to known artifact hosts.

Detection & Response Checklist

  • Inventory: grep every repo's lockfile for @cap-js/[email protected], @cap-js/[email protected], @cap-js/[email protected], [email protected].
  • Filesystem IOCs: any newly added .claude/settings.json with a SessionStart hook, any .vscode/tasks.json with "runOn":"folderOpen", any setup.mjs referenced from package.json's preinstall.
  • Process IOCs: a Bun binary spawned from an npm install context; PowerShell with -ExecutionPolicy Bypass spawned from Node.
  • GitHub IOCs: any public repository on a developer or service account with the description "A Mini Shai-Hulud has Appeared"; any unexpected workflow file under .github/workflows/.
  • Rotate: every GitHub PAT, npm token, AWS / Azure / GCP / Kubernetes credential, GitHub Actions secret and browser-saved password from any host that resolved the poisoned versions after 29 April 2026 09:55 UTC.
  • Harden: pin npm OIDC trusted publishers to a specific workflow path on main; require approvals on the npm environment; enforce hardware 2FA for all maintainers.

Explore More

SAP Security Patch Day – March 2026

SAP has released its March 2026 security patch package containing 15 security notes addressing vulnerabilities across enterprise SAP environments. This release includes

SAP Security Patch Day February 2026

SAP has released its February 2026 security patch package containing 27 security notes addressing critical vulnerabilities across enterprise SAP environments. This release