Mini Shai-Hulud Supply-Chain Campaign Compromises TanStack and Other npm, PyPI Packages

· Original article ↗

Summary

Socket reports malicious npm and PyPI package releases linked to Mini Shai-Hulud. The malware targets CI, cloud, and developer credentials, can propagate through package publishing, and prompted TanStack to remove affected versions and harden workflows.

Key points

  • Socket identified malicious code in 84 TanStack npm package artifacts; the article's later campaign update lists 1,069 affected packages across npm and PyPI.
  • The malware uses obfuscated payloads and package lifecycle hooks to execute during installation, targeting GitHub Actions and developer systems.
  • Credential targets include GitHub and npm tokens, AWS credentials and metadata services, Vault secrets, and Kubernetes service-account tokens.
  • The payload can use GitHub Actions OIDC publishing access to republish infected packages and can add persistence through Claude Code and VS Code configuration.
  • TanStack said the attack exploited a pull_request_target workflow and GitHub Actions cache poisoning to access its trusted-publisher workflow; it reported no stolen npm tokens.
  • TanStack deprecated affected versions, worked with npm to remove malicious tarballs, purged Actions caches, and hardened its workflows.
  • The article recommends rotating exposed secrets, reviewing developer environments and publishing logs, verifying package integrity, and restricting GitHub Actions OIDC permissions.

Article Details

Attack Vectors
  • Compromised npm packages distribute router_init.js directly and introduce a Git-based @tanstack/setup dependency whose prepare lifecycle hook executes tanstack_runner.js during installation.
  • TanStack's postmortem attributes initial compromise to chained pull_request_target abuse, GitHub Actions cache poisoning across the fork-to-base trust boundary, and extraction of an OIDC token from runner process memory.
  • According to TanStack, attacker-controlled code executed during workflow test/cleanup and published malicious packages directly through the project's OIDC trusted-publisher binding; npm tokens were not stolen and the publishing workflow itself was not compromised.
  • The implant harvests CI environment credentials, accesses cloud metadata and secrets APIs, and propagates by modifying and republishing package archives under compromised maintainer identities.
  • Stolen GitHub tokens enable repository modification through createCommitOnBranch, including malicious workflow definitions and developer-tool configuration files.
  • Developer workstation persistence uses Claude Code hooks and VS Code workspace tasks to re-execute copied payloads after the original package is removed.
  • Socket confirmed that guardrails-ai@0.10.1 executes malicious code on import on Linux, downloading a Python archive to /tmp/transformers.pyz and executing it with python3 without integrity verification.
  • Harvested credentials are exfiltrated through Session file-server and service-node infrastructure.
Defensive Notes
  • Hash router_init.js files throughout dependency trees and compare them with the published malware hashes.
  • Rotate secrets on systems that installed affected versions, prioritizing npm tokens, GitHub PATs and OIDC trusts, AWS credentials, Vault tokens, and Kubernetes service account tokens.
  • Revoke affected GitHub Actions OIDC federation grants and restore them only after validating workflow integrity.
  • Audit developer home and project .claude/ and .vscode/ directories for router_runtime.js, setup.mjs, unfamiliar hooks, and unexpected workspace tasks; package removal alone does not remove this persistence.
  • Review commits attributed to the spoofed Claude Code bot identity and unexpected package publishes from CI runners.
  • The article recommends blocking Session-related egress when that service is not required, favoring DNS-level controls because its service-node network is distributed.
  • Enforce pinned package integrity values and block CI on lockfile hash mismatches.
  • Disable OIDC permissions in workflows that do not require them and restrict id-token: write to the publishing job.
  • Do not treat valid Sigstore provenance alone as proof that a package is safe; attacker-executed CI code can produce valid attestations.
  • TanStack deprecated affected versions, engaged npm security to remove malicious tarballs, purged Actions caches, and hardened workflows with repository-owner guards and pinned third-party action references.
  • Socket reported that guardrails-ai@0.10.0 and earlier did not contain the newly introduced malicious code.

Indicators of compromise

TypeIndicatorContext
DOMAINgit-tanstack[.]comAttacker infrastructure serving the Python payload and displaying a credential-theft claim signed TeamPCP.
EMAILclaude@users[.]noreply[.]github[.]comSpoofed commit-author identity used by the implant when injecting malicious files into maintainer repositories; not evidence that the legitimate bot account is compromised.
MD5833fd59ebe66a4449982c6d18db656b4Published hash of the router_init.js / router_runtime.js malicious payload.
MD5b82e54923f7e440664d2d75bd31588caPublished hash of the tanstack_runner.js / router_init.js malicious variant.
SHA112ed9a3c1f73617aefdb740480695c04405d7b4bPublished hash of the router_init.js / router_runtime.js malicious payload.
SHA179ac49eedf774dd4b0cfa308722bc463cfe5885cSuspicious GitHub commit containing @tanstack/setup and the tanstack_runner.js payload with an automatic prepare execution hook.
SHA1e69bf4b3e84e7951a7b4ded8fee8822c57630cf8Commit identifier for an intercom/intercom-php artifact listed in the compromised-package table.
SHA1e7d582b98ca80690883175470e96f703ef6dc497Published hash of the tanstack_runner.js / router_init.js malicious variant.
SHA2562ec78d556d696e208927cc503d48e4b5eb56b31abc2870c2ed2e98d6be27fc96Published hash of the tanstack_runner.js / router_init.js malicious variant.
SHA256ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266cPublished hash of the router_init.js / router_runtime.js malicious payload.
URLhxxp[:]//filev2[.]getsession[.]org/file/Defanged Session file-server URL listed in the IOC section for the implant's credential exfiltration.
URLhxxps[:]//git-tanstack[.]com/transformers[.]pyzRemote malicious Python archive downloaded and executed by compromised guardrails-ai@0.10.1.

MITRE ATT&CK

T1027 · Obfuscated Files or InformationJavaScript payloads use rotating string arrays, hexadecimal dispatchers, control-flow flattening, dead-code injection, and an additional runtime string-decoding layer.T1036 · MasqueradingRepository-poisoning commits spoof the Claude Code bot author identity, while payload copies use router_runtime.js to blend into project tooling.T1059.006 · PythonCompromised guardrails-ai@0.10.1 executes a downloaded transformers.pyz archive using python3.T1059.007 · JavaScriptThe @tanstack/setup prepare hook executes the malicious tanstack_runner.js JavaScript payload with Bun.T1082 · System Information DiscoveryThe implant checks process.platform for linux, darwin, and win32 and inspects RUNNER_OS before selecting credential-harvesting behavior.T1105 · Ingress Tool TransferThe malicious guardrails-ai import code downloads transformers.pyz from attacker infrastructure into /tmp before execution.T1195.002 · Compromise Software Supply ChainThe implant modifies npm package archives and dependencies and republishes compromised versions that execute on downstream developer and CI systems.T1528 · Steal Application Access TokenTanStack's postmortem reports extraction of an OIDC token from GitHub Actions runner process memory; the implant also targets GitHub, npm, and Vault tokens.T1546 · Event Triggered ExecutionThe implant configures Claude Code tool-event hooks and VS Code folder-open tasks to re-execute copied payloads.T1550.001 · Application Access TokenStolen GitHub tokens authorize repository commits, and compromised OIDC identity authenticates malicious npm package publication.T1552.001 · Credentials In FilesThe payload targets the Kubernetes service account token file and the AWS web-identity token file as credential sources.T1552.005 · Cloud Instance Metadata APIThe implant requests EC2 IMDSv2 session tokens and accesses EC2 IAM and ECS metadata endpoints to harvest credentials.

Threat Actors

Vendors

Products

Bunpackage.json defines a package named @tanstack/setup and registers a prepare lifecycle hook that executes bun run tanstack_runner.js && exit 1. Since npm lifecycle hooks execute automatically when installing git-basedClaude Codefor the author claude@users.noreply.github.com that were not initiated through the legitimate Claude Code GitHub App. Use git log --all --author=claude@users.noreply.github.com to locate them; revert andGitHub Actionspackages were modified to add a suspected credential stealer targeting various CI systems, including Github Actions. All packages were flagged by Socket AI Scanner in six minutes or less after publication.HashiCorp Vaultcombines a credential-harvesting engine targeting GitHub Actions, AWS (IMDS, Secrets Manager, SSM), HashiCorp Vault, and Kubernetes with a worm propagation mechanism that steals an npm OIDC token from GitHub ActionsKubernetesnpm tokens, GitHub PATs/OIDC trusts, AWS credentials (static keys and instance roles), Vault tokens, Kubernetes service account tokens.Node.jsThe unref() call ensures Node.js does not wait for the child before exiting, making the parent's exit appear completely normal. Once running detached, the implant writes copies of itself into two developer toolingnpmThe Socket Threat Research team detected a compromise across 84 npm package artifacts in the tanstack namespace. Affected packages were modified to add a suspected credential stealer targeting various CI systems,OpenSearchUpdate: OpenSearch, Mistral AI, and Guardrails AI Added to Campaign - 2026-05-12 03:05:38 UTC#PyPISocket is continuing to track new compromised package artifacts tied to the Mini Shai-Hulud campaign across npm and PyPI.SessionBlock egress to filev2.getsession[.]org and related Session infrastructure at the perimeter if not in active use. The IP range for Session's service node network is distributed, so DNS-level blocking of .getsession.orgVS CodePersistence is achieved by writing copies of itself into Claude Code's hook directory (.claude/) and VS Code's task runner (.vscode/tasks.json) to survive across developer workstation reboots, extending the worm

Tools

Industries

Related Articles