Mini Shai-Hulud Targets SAP-Related npm Packages With Bun Payloads and IDE Persistence

· Original article ↗

Summary

StepSecurity reports four compromised SAP-related npm packages carrying a Bun-based credential stealer. Its analysis details npm worm propagation, GitHub Actions secret theft, encrypted exfiltration and persistence through Claude Code and VS Code hooks.

Key points

  • StepSecurity identifies [email protected], @cap-js/[email protected], @cap-js/[email protected] and @cap-js/[email protected] as compromised, with identical preinstall loaders launching an obfuscated 11.6 MB payload through Bun.
  • Researchers attribute the mbt release to a stolen npm token and describe abuse of a compromised developer GitHub account and repository-wide OIDC publishing trust for the @cap-js releases.
  • A controlled GitHub Actions installation captured the payload spawning Python to read Runner.Worker memory through /proc and extract serialized secrets.
  • Recovered code harvests npm, GitHub and cloud credentials, injects workflows to collect repository secrets, and uses stolen npm tokens to publish infected packages directly through registry APIs.
  • The payload installs Claude Code SessionStart hooks and VS Code folder-open tasks in accessible repositories to enable re-execution and further propagation.
  • Collected data is encrypted with AES-256-GCM, with keys wrapped using RSA-4096, before exfiltration through GitHub repositories. The payload also exits when it detects a Russian locale.
  • Recommended recovery includes removing compromised versions, rotating exposed credentials, auditing unauthorized npm releases and GitHub repositories, and removing malicious IDE configurations and injected workflows across branches.

Article Details

Attack Vectors
  • Compromised npm releases use a preinstall hook to launch setup.mjs, download Bun, and execute an obfuscated credential-stealing payload.
  • A stolen static npm automation token was used to publish [email protected]; the source does not establish how the token was initially obtained.
  • A compromised SAP developer GitHub account was used to modify release automation and abuse repository-wide npm OIDC trust, exposing a double-base64-encoded publishing token in workflow logs.
  • Stolen npm tokens enable autonomous propagation through direct registry API publishing of infected package versions.
  • Repository modifications install VSCode folderOpen tasks and Claude Code SessionStart hooks that re-execute copied malware.
  • Injected GitHub Actions workflows serialize repository secrets into downloadable workflow artifacts.
  • Credential collection targets local files, environment variables, cloud secret stores, and readable memory of the GitHub Actions Runner.Worker process.
  • Encrypted stolen data is committed to public repositories created under victim accounts; an alternative sender uses an embedded attacker token to locate a C2 repository.
Defensive Notes
  • Check for [email protected], @cap-js/[email protected], @cap-js/[email protected], and @cap-js/[email protected]. The article's unpublishing paragraph reverses the postgres and db-service version assignments relative to its confirmed-package list.
  • The source recommends removing compromised releases and installing [email protected], @cap-js/[email protected], @cap-js/[email protected], or @cap-js/[email protected] with --ignore-scripts.
  • Rotate credentials accessible on affected developer machines and CI jobs, including npm and GitHub tokens, cloud credentials, SSH keys, Kubernetes tokens, environment secrets, and accessible cloud secret-store contents.
  • Inspect all repository branches for malicious .vscode/tasks.json, .claude/settings.json, copied execution.js payloads, and setup.mjs loaders; the malware targets up to 50 branches.
  • Remove the dependabout/github_actions/format/setup-formatter branch and inspect .github/workflows/format-check.yml for toJSON(secrets) and the format-results artifact.
  • Find and remove unauthorized public repositories with the description 'A Mini Shai-Hulud has Appeared' or the documented Dune-themed naming pattern.
  • Audit npm publishing history for unauthorized versions and unpublish infected releases; pin known-good exact dependency versions.
  • Monitor Runner.Worker memory access through /proc and unexpected processes during package installation. StepSecurity reports that Harden-Runner flagged this behavior in its controlled test.
  • Treat discovered exfiltration repositories as evidence of potential credential exposure even when their contents are encrypted.

Indicators of compromise

TypeIndicatorContext
SHA2564066781fa830224c8bbcc3aa005a396657f9c8f9016f9a64ad44a9d7f5f45e34Malicious setup.mjs loader hash reported identical across all four compromised packages.
SHA2566f933d00b7d05678eb43c90963a80b8947c4ae6830182f89df31da9f568fea95Malicious execution.js payload in @cap-js/sqlite.
SHA25680a3d2877813968ef847ae73b5eeeb70b9435254e74d7f07d8cf4057f0a710acCredential-stealing execution.js payload in [email protected].

MITRE ATT&CK

T1003 · OS Credential DumpingThe Python collector dumps readable Runner.Worker address-space segments and extracts plaintext secrets using the runner's internal serialization format.T1027 · Obfuscated Files or InformationThe 11.6 MB payload uses rotated string tables, a custom base64 alphabet, and the ctf-scramble-v2 cipher to conceal sensitive strings.T1036 · MasqueradingMalicious commits impersonate claude or dependabot[bot], use routine maintenance messages, and create a dependabout branch resembling Dependabot activity.T1059.006 · PythonAn embedded Python script scans /proc and reads Runner.Worker memory to recover CI secrets.T1059.007 · JavaScriptThe preinstall hook executes setup.mjs with Node.js, then launches the JavaScript execution.js payload under Bun.T1070.004 · File DeletionThe loader deletes its temporary Bun runtime directory after payload execution.T1078 · Valid AccountsThe attacker used a compromised SAP developer GitHub account and stolen npm publishing credentials to modify release workflows and publish malicious releases.T1140 · Deobfuscate/Decode Files or InformationThe malware decodes scrambled strings and decompresses its embedded RSA public key at runtime.T1195.002 · Compromise Software Supply ChainFour compromised SAP-related npm packages distribute a malicious preinstall loader and credential stealer.T1528 · Steal Application Access TokenCollectors steal npm tokens, GitHub PATs and OAuth tokens, and cloud access credentials for subsequent access and propagation.T1552.001 · Credentials In FilesThe stealer harvests credential files including .npmrc, cloud credential stores, .git-credentials, Kubernetes configuration, and .env files.T1552.004 · Private KeysFilesystem harvesting includes private SSH keys such as ~/.ssh/id_rsa, ~/.ssh/id_ed25519, and host-key paths.T1552.005 · Cloud Instance Metadata APICredential collection references cloud instance and task metadata endpoints, including EC2 IMDS, ECS task metadata, and Azure IMDS.T1567.001 · Exfiltration to Code RepositoryThe payload commits encrypted stolen credentials into public GitHub repositories created on victim accounts.T1614.001 · System Language DiscoveryThe payload checks Intl locale and POSIX locale environment variables and exits when they contain ru.

Threat Actors

Malware

Vendors

Products

@cap-js/db-serviceFour confirmed compromised packages, [email protected], @cap-js/[email protected], @cap-js/[email protected], and @cap-js/[email protected], all carry an identical malicious preinstall hook that bootstraps the Bun JavaScript runtime@cap-js/postgresFour confirmed compromised packages, [email protected], @cap-js/[email protected], @cap-js/[email protected], and @cap-js/[email protected], all carry an identical malicious preinstall hook that bootstraps the Bun JavaScript runtime@cap-js/sqliteFour confirmed compromised packages, [email protected], @cap-js/[email protected], @cap-js/[email protected], and @cap-js/[email protected], all carry an identical malicious preinstall hook that bootstraps the Bun JavaScript runtimeBunand @cap-js/[email protected], all carry an identical malicious preinstall hook that bootstraps the Bun JavaScript runtime and executes a heavily obfuscated 11.6 MB credential stealer. The setup.mjs loader isClaude Code‍The payload commits a .claude/settings.json abusing Claude Code's SessionStart hook and a .vscode/tasks.json with "runOn": "folderOpen" into every accessible repo, signed [email protected] with "chore:GitHub ActionsTo observe the malware's behavior at runtime, we installed @cap-js/[email protected] in a controlled GitHub Actions workflow with StepSecurity Harden-Runner enabled in audit mode. Harden-Runner monitors all outbound networkHarden-RunnerStepSecurity’s OSS AI Package Analyst and Harden-Runner detected this compromise within minutes of the first malicious publish. We responsibly disclosed[1][2] the breach by creating GitHub issues on the affectedmbtFour confirmed compromised packages, [email protected], @cap-js/[email protected], @cap-js/[email protected], and @cap-js/[email protected], all carry an identical malicious preinstall hook that bootstraps the Bun JavaScript runtimenpmaction: a developer or CI/CD pipeline installs the first compromised package, the stealer harvests their npm token, and the worm publishes itself to every other package that token can reach. Stolen credentials areVSCode‍The payload commits a .claude/settings.json abusing Claude Code's SessionStart hook and a .vscode/tasks.json with "runOn": "folderOpen" into every accessible repo, signed [email protected] with "chore:

Tools

Countries

Related Articles