Notes

Analysis and Detection Guide for the Mini Shai-Hulud Supply Chain Attack

2026-05-13 #NPM#Security

On May 11, 2026, a coordinated supply chain attack targeting the npm and PyPI ecosystems occurred. This attack simultaneously affected multiple well-known npm and PyPI packages.

This was not a run-of-the-mill malicious package injection event. Instead of simply relying on stolen npm credentials, the attackers leveraged GitHub Actions, cache poisoning, OIDC Token abuse, malicious dependencies, persistent daemon processes, and multi-channel C2 infrastructure to construct a complete supply chain intrusion vector.

Specific release times of the malicious TanStack-related versions: Beijing Time (UTC+8) May 12, between 3:20 AM and 3:26 AM.


1. Incident Overview

This attack affected several high-value packages across both the npm and PyPI ecosystems.

Mainly affected packages:

  • Packages under @tanstack, such as @tanstack/react-router—one of the most widely used routing libraries in the React ecosystem with approximately 12 million weekly downloads—and @tanstack/vue-router was also affected.
  • Packages under @uipath, including tools, CLIs, and Agent SDKs related to the UiPath Enterprise Automation Platform.
  • @mistralai/mistralai, the official Mistral AI TypeScript client.
  • @opensearch-project/opensearch
  • mistralai: 2.4.6 on PyPI
  • guardrails-ai: 0.10.1 on PyPI

The npm security team has noticed the attack and quickly removed the malicious versions.

You can view the list of known affected packages at the end of this article.

2. TanStack Attack Chain: GitHub Actions Becomes the Breakthrough

The compromise of TanStack stemmed from a complex exploit chain targeting GitHub Actions (involving three vulnerabilities):

The attack chain was roughly as follows:

  1. The attacker forked the TanStack/router repository.
  2. The attacker renamed the forked repository to zblgg/configuration to bypass fork list audits.
  3. The attacker submitted a Pull Request, triggering the pull_request_target workflow in the target repository.
  4. This workflow incorrectly checked out and executed code from the attacker's fork.
  5. The attacker poisoned the GitHub Actions cache, writing a malicious pnpm store into the cache.
  6. When a subsequent legitimate maintainer's PR was merged into the main branch, the release workflow restored the poisoned cache.
  7. A binary controlled by the attacker read the OIDC Token from the memory space of the GitHub Actions Runner process.
  8. The attacker used these Tokens to publish malicious versions of the npm packages.

The most notable aspect of this vector is that the attacker did not need to steal npm credentials to publish malicious packages.

This demonstrates that in modern software supply chains, package registry accounts are no longer the only critical assets. CI/CD workflows, caches, OIDC Tokens, publishing permissions, and workflow boundaries are also high-value attack surfaces.

UiPath Infection Variant

Shortly after @tanstack was compromised, @uipath was also breached. These packages used a preinstall script (node setup.mjs) to download the Bun runtime environment and execute a malicious payload. This is identical to the delivery mechanism seen in the previous SAP compromise. The UiPath variant used a re-obfuscated payload and a different Campaign Key, but connected to the same C2 (Command and Control) infrastructure.

3. Malicious Payload: Credential Theft and Worm-like Propagation

This malicious payload has self-propagation capabilities, primarily targeting the theft of the following types of credentials and identity materials:

It mainly targets:

  • CI/CD tokens (GitHub Actions OIDC, GitLab, CircleCI)
  • Cloud service credentials (AWS IMDSv2, GCP, Azure)
  • Kubernetes service accounts
  • HashiCorp Vault
  • Package registry tokens

Worm Behavior: The malware uses stolen npm tokens and GitHub Actions OIDC tokens to publish poisoned versions of other packages that the victim has write access to, thereby spreading rapidly like a worm throughout the npm ecosystem.

Destructive Local Daemon Process

If the malware discovers a valid GitHub Personal Access Token starting with ghp_ or an OAuth Token starting with gho_, it installs a persistent daemon process locally:

macOS:

1
~/Library/LaunchAgents/com.user.gh-token-monitor.plist

Linux:

1
~/.config/systemd/user/gh-token-monitor.service

If it receives a 40X error due to the GitHub token being revoked, the process will attempt to execute rm -rf ~/, wiping the user's home directory completely! However, this daemon process will automatically exit after running for 24 hours.

Note: Similar to previous Mini Shai-Hulud variants, the malware checks if the system's language is set to Russian. If so, it terminates immediately and does not steal any data.

4. Detection Guide

  1. Audit Packages: Search lockfiles and CI logs for affected package versions. Check if router_init.js or setup.mjs exists in the package root directory.
  2. Detect and Clean Persistent Threats: Search for the gh-token-monitor daemon process on developer machines and delete it (refer to the paths in the indicators below).
  3. Rotate All Credentials: If you suspect you have been affected, immediately rotate GitHub tokens, npm tokens, AWS credentials, Vault tokens, Kubernetes service accounts, and CI/CD secrets.

    Warning: Before revoking GitHub tokens, make sure to inspect and remove the persistent daemon process to avoid triggering the malware's destructive command (rm -rf ~/).

  4. Inspect IDE Directories: Check for leftover router_runtime.js or setup.mjs files in .claude/ and .vscode/ directories. These files might persist even after running npm uninstall.
  5. Block C2 Target Domains: Block git-tanstack.com and *.getsession.org at the DNS/proxy level.

Files

File Name Details SHA-256 / SHA-1
router_init.js 2,341,681 bytes SHA256:
``ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266c`
router_init.js 2,339,346 bytes SHA256:
2ec78d556d696e208927cc503d48e4b5eb56b31abc2870c2ed2e98d6be27fc96
SHA1:
e7d582b98ca80690883175470e96f703ef6dc497
setup.mjs 5,047 bytes SHA256:
2258284d65f63829bd67eaba01ef6f1ada2f593f9bbe41678b2df360bd90d3df
SHA1:
12f35b1081b17d21815b35feb57ab03d02482116
opensearch_init.js - SHA1:
820fa07a7328b6cf2b417078e103721d4d8f2e79

Network IOCs

Type Target
C2 Domain git-tanstack.com
Session Seed Nodes seed1.getsession.org, seed2.getsession.org, seed3.getsession.org
Session File Server filev2.getsession.org
C2 IP Address 83.142.209.194
PyPI Payload URL git-tanstack.com/tmp/transformers.pyz

Other Indicators

Category Indicator Description
Service Name gh-token-monitor
macOS Path ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
Linux Path ~/.config/systemd/user/gh-token-monitor.service
Runtime Artifacts router_runtime.js , tanstack_runner.js
Hook Execution Command preinstall: node setup.mjs
Malicious Git Dependency github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c
Specific Execution Env Bun Version 1.3.13

5. Affected Packages

PyPI

NPM

Package Affected Versions
@beproduct/nestjs-auth 0.1.2, 0.1.3, 0.1.4, 0.1.5, 0.1.6, 0.1.7, 0.1.8, 0.1.9, 0.1.10, 0.1.11, 0.1.12, 0.1.13, 0.1.14, 0.1.15, 0.1.16, 0.1.17, 0.1.18, 0.1.19
@cap-js/db-service 2.10.1
@cap-js/postgres 2.2.2
@cap-js/sqlite 2.2.2
@dirigible-ai/sdk 0.6.2, 0.6.3
@draftauth/client 0.2.1, 0.2.2
@draftauth/core 0.13.1, 0.13.2
@draftlab/auth 0.24.1, 0.24.2
@draftlab/auth-router 0.5.1, 0.5.2
@draftlab/db 0.16.1, 0.16.2
@mesadev/rest 0.28.3
@mesadev/saguaro 0.4.22
@mesadev/sdk 0.28.3
@mistralai/mistralai 2.2.2, 2.2.3, 2.2.4
@mistralai/mistralai-azure 1.7.1, 1.7.2, 1.7.3
@mistralai/mistralai-gcp 1.7.1, 1.7.2, 1.7.3
@ml-toolkit-ts/preprocessing 1.0.2, 1.0.3
@ml-toolkit-ts/xgboost 1.0.3, 1.0.4
@opensearch-project/opensearch 3.5.3, 3.6.2, 3.7.0, 3.8.0
@squawk/airport-data 0.7.4, 0.7.5, 0.7.6, 0.7.7, 0.7.8
@squawk/airports 0.6.2, 0.6.3, 0.6.4, 0.6.5, 0.6.6
@squawk/airspace 0.8.1, 0.8.2, 0.8.3, 0.8.4, 0.8.5
@squawk/airspace-data 0.5.3, 0.5.4, 0.5.5, 0.5.6, 0.5.7
@squawk/airway-data 0.5.4, 0.5.5, 0.5.6, 0.5.7, 0.5.8
@squawk/airways 0.4.2, 0.4.3, 0.4.4, 0.4.5, 0.4.6
@squawk/fix-data 0.6.4, 0.6.5, 0.6.6, 0.6.7, 0.6.8
@squawk/fixes 0.3.2, 0.3.3, 0.3.4, 0.3.5, 0.3.6
@squawk/flight-math 0.5.4, 0.5.5, 0.5.6, 0.5.7, 0.5.8
@squawk/flightplan 0.5.2, 0.5.3, 0.5.4, 0.5.5, 0.5.6
@squawk/geo 0.4.4, 0.4.5, 0.4.6, 0.4.7, 0.4.8
@squawk/icao-registry 0.5.2, 0.5.3, 0.5.4, 0.5.5, 0.5.6
@squawk/icao-registry-data 0.8.4, 0.8.5, 0.8.6, 0.8.7, 0.8.8
@squawk/mcp 0.9.1, 0.9.2, 0.9.3, 0.9.4, 0.9.5
@squawk/navaid-data 0.6.4, 0.6.5, 0.6.6, 0.6.7, 0.6.8
@squawk/navaids 0.4.2, 0.4.3, 0.4.4, 0.4.5, 0.4.6
@squawk/notams 0.3.6, 0.3.7, 0.3.8, 0.3.9, 0.3.10
@squawk/procedure-data 0.7.3, 0.7.4, 0.7.5, 0.7.6, 0.7.7
@squawk/procedures 0.5.2, 0.5.3, 0.5.4, 0.5.5, 0.5.6
@squawk/types 0.8.1, 0.8.2, 0.8.3, 0.8.4, 0.8.5
@squawk/units 0.4.3, 0.4.4, 0.4.5, 0.4.6, 0.4.7
@squawk/weather 0.5.6, 0.5.7, 0.5.8, 0.5.9, 0.5.10
@supersurkhet/cli 0.0.2, 0.0.3, 0.0.4, 0.0.5, 0.0.6, 0.0.7
@supersurkhet/sdk 0.0.2, 0.0.3, 0.0.4, 0.0.5, 0.0.6, 0.0.7
@tallyui/components 1.0.1, 1.0.2, 1.0.3
@tallyui/connector-medusa 1.0.1, 1.0.2, 1.0.3
@tallyui/connector-shopify 1.0.1, 1.0.2, 1.0.3
@tallyui/connector-vendure 1.0.1, 1.0.2, 1.0.3
@tallyui/connector-woocommerce 1.0.1, 1.0.2, 1.0.3
@tallyui/core 0.2.1, 0.2.2, 0.2.3
@tallyui/database 1.0.1, 1.0.2, 1.0.3
@tallyui/pos 0.1.1, 0.1.2, 0.1.3
@tallyui/storage-sqlite 0.2.1, 0.2.2, 0.2.3
@tallyui/theme 0.2.1, 0.2.2, 0.2.3
@tanstack/arktype-adapter 1.166.12, 1.166.15
@tanstack/eslint-plugin-router 1.161.9, 1.161.12
@tanstack/eslint-plugin-start 0.0.4, 0.0.7
@tanstack/history 1.161.9, 1.161.12
@tanstack/nitro-v2-vite-plugin 1.154.12, 1.154.15
@tanstack/react-router 1.169.5, 1.169.8
@tanstack/react-router-devtools 1.166.16, 1.166.19
@tanstack/react-router-ssr-query 1.166.15, 1.166.18
@tanstack/react-start 1.167.68, 1.167.71
@tanstack/react-start-client 1.166.51, 1.166.54
@tanstack/react-start-rsc 0.0.47, 0.0.50
@tanstack/react-start-server 1.166.55, 1.166.58
@tanstack/router-cli 1.166.46, 1.166.49
@tanstack/router-core 1.169.5, 1.169.8
@tanstack/router-devtools 1.166.16, 1.166.19
@tanstack/router-devtools-core 1.167.6, 1.167.9
@tanstack/router-generator 1.166.45, 1.166.48
@tanstack/router-plugin 1.167.38, 1.167.41
@tanstack/router-ssr-query-core 1.168.3, 1.168.6
@tanstack/router-utils 1.161.11, 1.161.14
@tanstack/router-vite-plugin 1.166.53, 1.166.56
@tanstack/solid-router 1.169.5, 1.169.8
@tanstack/solid-router-devtools 1.166.16, 1.166.19
@tanstack/solid-router-ssr-query 1.166.15, 1.166.18
@tanstack/solid-start 1.167.65, 1.167.68
@tanstack/solid-start-client 1.166.50, 1.166.53
@tanstack/solid-start-server 1.166.54, 1.166.57
@tanstack/start-client-core 1.168.5, 1.168.8
@tanstack/start-fn-stubs 1.161.9, 1.161.12
@tanstack/start-plugin-core 1.169.23, 1.169.26
@tanstack/start-server-core 1.167.33, 1.167.36
@tanstack/start-static-server-functions 1.166.44, 1.166.47
@tanstack/start-storage-context 1.166.38, 1.166.41
@tanstack/valibot-adapter 1.166.12, 1.166.15
@tanstack/virtual-file-routes 1.161.10, 1.161.13
@tanstack/vue-router 1.169.5, 1.169.8
@tanstack/vue-router-devtools 1.166.16, 1.166.19
@tanstack/vue-router-ssr-query 1.166.15, 1.166.18
@tanstack/vue-start 1.167.61, 1.167.64
@tanstack/vue-start-client 1.166.46, 1.166.49
@tanstack/vue-start-server 1.166.50, 1.166.53
@tanstack/zod-adapter 1.166.12, 1.166.15
@taskflow-corp/cli 0.1.24, 0.1.25, 0.1.26, 0.1.27, 0.1.28, 0.1.29
@tolka/cli 1.0.2, 1.0.3, 1.0.4, 1.0.5, 1.0.6
@uipath/access-policy-sdk 0.3.1
@uipath/access-policy-tool 0.3.1
@uipath/admin-tool 0.1.1
@uipath/agent-sdk 1.0.2
@uipath/agent-tool 1.0.1
@uipath/agent.sdk 0.0.18
@uipath/aops-policy-tool 0.3.1
@uipath/ap-chat 1.5.7
@uipath/api-workflow-tool 1.0.1
@uipath/apollo-core 5.9.2
@uipath/apollo-react 4.24.5
@uipath/apollo-wind 2.16.2
@uipath/auth 1.0.1
@uipath/case-tool 1.0.1
@uipath/cli 1.0.1
@uipath/codedagent-tool 1.0.1
@uipath/codedagents-tool 0.1.12
@uipath/codedapp-tool 1.0.1
@uipath/common 1.0.1
@uipath/context-grounding-tool 0.1.1
@uipath/data-fabric-tool 1.0.2
@uipath/docsai-tool 1.0.1
@uipath/filesystem 1.0.1
@uipath/flow-tool 1.0.2
@uipath/functions-tool 1.0.1
@uipath/gov-tool 0.3.1
@uipath/identity-tool 0.1.1
@uipath/insights-sdk 1.0.1
@uipath/insights-tool 1.0.1
@uipath/integrationservice-sdk 1.0.2
@uipath/integrationservice-tool 1.0.2
@uipath/llmgw-tool 1.0.1
@uipath/maestro-sdk 1.0.1
@uipath/maestro-tool 1.0.1
@uipath/orchestrator-tool 1.0.1
@uipath/packager-tool-apiworkflow 0.0.19
@uipath/packager-tool-bpmn 0.0.9
@uipath/packager-tool-case 0.0.9
@uipath/packager-tool-connector 0.0.19
@uipath/packager-tool-flow 0.0.19
@uipath/packager-tool-functions 0.1.1
@uipath/packager-tool-webapp 1.0.6
@uipath/packager-tool-workflowcompiler 0.0.16
@uipath/packager-tool-workflowcompiler-browser 0.0.34
@uipath/platform-tool 1.0.1
@uipath/project-packager 1.1.16
@uipath/resource-tool 1.0.1
@uipath/resourcecatalog-tool 0.1.1
@uipath/resources-tool 0.1.11
@uipath/robot 1.3.4
@uipath/rpa-legacy-tool 1.0.1
@uipath/rpa-tool 0.9.5
@uipath/solution-packager 0.0.35
@uipath/solution-tool 1.0.1
@uipath/solutionpackager-sdk 1.0.11
@uipath/solutionpackager-tool-core 0.0.34
@uipath/tasks-tool 1.0.1
@uipath/telemetry 0.0.7
@uipath/test-manager-tool 1.0.2
@uipath/tool-workflowcompiler 0.0.12
@uipath/traces-tool 1.0.1
@uipath/ui-widgets-multi-file-upload 1.0.1
@uipath/uipath-python-bridge 1.0.1
@uipath/vertical-solutions-tool 1.0.1
@uipath/vss 0.1.6
@uipath/widget.sdk 1.2.3
agentwork-cli 0.1.4, 0.1.5
cmux-agent-mcp 0.1.3, 0.1.4, 0.1.5, 0.1.6, 0.1.7, 0.1.8
cross-stitch 1.1.3, 1.1.4, 1.1.5, 1.1.6, 1.1.7
git-branch-selector 1.3.3, 1.3.4, 1.3.5, 1.3.6, 1.3.7
git-git-git 1.0.8, 1.0.9, 1.0.10, 1.0.11, 1.0.12
guardrails-ai 0.10.1
intercom-client 7.0.4
lightning 2.6.2, 2.6.3
mbt 1.2.48
mistralai 2.4.6
ml-toolkit-ts 1.0.4, 1.0.5
nextmove-mcp 0.1.3, 0.1.4, 0.1.5, 0.1.6, 0.1.7
safe-action 0.8.3, 0.8.4
ts-dna 3.0.1, 3.0.2, 3.0.3, 3.0.4, 3.0.5
wot-api 0.8.1, 0.8.2, 0.8.3, 0.8.4

Conclusion

This attack illustrates a new trend in supply chain threats: attackers no longer limit their focus to package registry accounts. Instead, they chain together GitHub Actions, caching, OIDC, developer terminals, CI/CD secrets, and open-source release workflows into a cohesive exploit path.

For security teams, simply "upgrading dependencies" is no longer sufficient. Effective protection must cover the entire pipeline—from code commits, CI execution, credential issuing, and package publishing, down to the developer's local environment.

This incident serves as a critical reminder: CI/CD is part of the production environment, dependencies are part of the executable codebase, and developer machines are part of the supply chain boundary.

References

Comments
Share

Comments