Someone just published a malicious version of a package your developers installed this morning. They used the legitimate CI/CD pipeline. The artifact has valid provenance.
Between May 11 and 12, 2026, a self-propagating worm swept through the npm ecosystem, compromising over 200 packages maintained by TanStack, Mistral AI, UiPath, and Guardrails AI. The campaign calls itself Mini Shai-Hulud, and unlike most supply chain attacks you have read about, this one does not wait for your developers to run the compromised code. It executes at install.
For MSPs managing development environments, CI/CD pipelines, or any tenant running JavaScript tooling, the question is not whether this affected your clients, the question is whether you have the visibility to know.
The campaign calls itself Mini Shai-Hulud. The threat actor is TeamPCP.
What Actually Happened
The first wave hit in late April. Six packages, including SAP CAP components and intercom clients, were compromised via stolen npm tokens. Relatively contained. The second wave, which is still unfolding as of this writing, is a different class of problem.
Wave two started with TanStack Router. The initial access vector was a GitHub Actions abuse pattern involving pull_request_target workflows, cache poisoning, and OIDC token extraction from runner memory. Once the attackers had a valid GitHub token and npm publishing rights, the worm did the rest.
The compromised package publishes a new malicious version. That version’s package.json adds an optionalDependencies entry pointing to a malicious orphan commit at github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c, attributed to a GitHub user voicproducoes. The prepare script runs bun run tanstack_runner.js && exit 1.
The Bun runtime executes a heavily obfuscated 2.xMB JavaScript payload (router_init.js) that harvests credentials from 100+ file paths, environment variables, and process memory. Those credentials include GitHub tokens, npm tokens, AWS/GCP/Azure credentials, Kubernetes configs, HashiCorp Vault tokens, SSH keys, and crypto wallet material.
Using the stolen tokens, the malware enumerates all other npm packages owned by the compromised maintainer and publishes infected versions of them as well. Self-propagating. Each new infection hands the worm a fresh set of maintainer credentials. The blast radius scales with the size of the dependency graph.
By May 12, the count was somewhere between 160 and 200+ packages. Lists are still being updated.
No Slack account needed.
Why Security Controls Cannot Catch This
SLSA provenance is supposed to help. The attestations on these malicious versions were valid because they were built by the legitimate pipelines. The provenance verified that the build ran on GitHub Actions. It said nothing about what was injected into the build environment before the artifact was produced. Valid provenance on a compromised build is not a security control.
npm’s package signing tells you a package was signed. It does not tell you that the signing key wasn’t on a machine running router_init.js at the time.
SCA tools check packages against databases of known vulnerable versions. A package published yesterday that is not yet in any advisory database will pass clean. The malicious TanStack versions had a window of hours before they were detected. For packages with millions of weekly downloads, hours are enough.
The payload in router_init.js (SHA-256: ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266c) is 2.xMB of heavily obfuscated JavaScript. Most SAST tools that run in CI/CD do not perform behavioral analysis on optional dependencies at install time. They are doing pattern matching on the source.
The Payload Behavior
The malware runs at package install, not at runtime. That distinction matters because it means it fires on developer workstations, in CI/CD runners, in Docker build stages, in any environment where someone runs npm install.
Credential harvesting targets are broad. The malware scans 100+ file paths covering common credential storage locations on macOS, Linux, and Windows. It reads environment variables wholesale. It hits process memory looking for GitHub Actions runner secrets. It makes HTTP requests to 169.254.169.254 (AWS IMDS), 169.254.170.2 (ECS task metadata), and 127.0.0.1:8200 (Vault API).
Exfiltration goes three ways. First, via the Session Protocol using filev2.getsession.org. Second, via git-tanstack.com for PyPI-related material. Third, via GitHub GraphQL dead-drops. The dead-drop commits come from [email protected], with commit messages like chore: update dependencies, on branches named after Dune terminology: dependabot/github_actions/format/fremen, /sardaukar, and similar. The repositories carrying stolen data have descriptions that read, “Mini Shai-Hulud has appeared.”
Persistence is where this gets uncomfortable. On Linux, the malware installs a systemd unit. On macOS, it installs a LaunchAgent. The service is named gh-token-monitor. If the stolen GitHub token is revoked, the service executes rm -rf ~. The npm token itself is published with the description IfYouRevokeThisTokenItWillWipeTheComputerOfTheOwner. This is not malware trying to stay quiet. It is malware posing a threat.
IDE hooks land in .vscode/tasks.json, .vscode/setup.mjs, .claude/settings.json, and .claude/router_runtime.js. Injected GitHub Actions workflows appear as .github/workflows/codeql_analysis.yml if they were. The presence of .claude/ targeting is notable. Claude Code is part of the targeted surface.

IOC’s
We are actively scanning client environments and tracing any breadcrumbs this campaign may have left behind. If you manage development environments, CI/CD pipelines, or any tenant running JavaScript or Python tooling, the investigation is already running. The question is what it finds.
Below is a link to the IOC’s. This list is a partial list, as of May 12.
https://github.com/guardzcom/security-research-labs/blob/main/Threat-Intel/IOCs/Shai-Hulud/README.md
Insights
Check for gh-token-monitor before revoking anything. The destructive wipe triggers on token revocation, not on detection. Isolate the machine first, then pull credentials. Revoking on a live infected host is the trigger.
@tanstack/setup In any dependency tree, there is a hard stop. That package does not exist in the legitimate TanStack org. Its presence means the worm has already run. Grep every package.json and package-lock.json across client environments now.
Valid provenance is not a detection control. The malicious versions carried valid SLSA Build Level 3 attestations because the pipeline was compromised before the build ran. Provenance verifies where the artifact was built, not what ran inside that environment beforehand.
Hunt the dead drops, not just the domains. Blocking the C2 domains is necessary but not sufficient. The exfil also runs through legitimate GitHub infrastructure via GraphQL dead-drops on branches named after Dune terminology. Those will never trigger a domain blocklist.
This campaign did not steal credentials to publish malicious packages. It hijacked the pipeline itself and published through it. Every GitHub Actions workflow with pull_request_target, and every cached dependency, every OIDC token issued to a runner is a potential injection point.
Track Guardz
This campaign is consistent with the broader shift we documented in the 2026 MSP Threat Report. We are tracking Mini Shai-Hulud actively and will publish updates as the indicator list grows.
Follow @GuardzCyber on X for real-time threat updates, IOC drops, and campaign developments as they happen.
For more research artifacts related to this campaign, see the Guardz Security Research Labs repository. Star it, watch it, and pull updates as the indicator set evolves.