{"slug": "mass-supply-chain-attack-hits-tanstack-mistral-ai-npm-and-pypi-packages", "title": "Mass Supply Chain Attack Hits TanStack, Mistral AI npm and PyPI Packages", "summary": "On May 11, 2026, a coordinated supply chain attack compromised over 170 npm packages and 2 PyPI packages, totaling 404 malicious versions, targeting major projects including the entire TanStack router ecosystem, Mistral AI's SDK suite, UiPath's automation tooling, OpenSearch, and Guardrails AI. The attack, one of the largest registry poisoning events of 2026, spanned both npm and PyPI in a single campaign, using payloads delivered from the attacker-controlled domain git-tanstack[.]com. PyPI has since quarantined the affected projects, and Cloudflare has flagged the domain as a suspected phishing site.", "body_md": "# Mass Supply Chain Attack Hits TanStack, Mistral AI npm and PyPI Packages\n\n### Table of Contents\n\n## TL;DR\n\nA coordinated supply chain attack on May 11, 2026 compromised over 170 npm packages and 2 PyPI packages, totaling 404 malicious versions. The attacker hit the entire TanStack router ecosystem (42 packages), Mistral AI’s SDK suite (on both npm and PyPI), UiPath’s automation tooling (65 packages), OpenSearch (1.3M weekly npm downloads), and Guardrails AI (PyPI). This is one of the largest coordinated registry poisoning events observed in 2026, and the first to span both npm and PyPI in a single campaign.\n\n[Package Manager Guard](https://github.com/safedep/pmg) (PMG) helps protect developers from open source software supply chain attacks using threat intelligence, install-time policy enforcement, and OS-native sandboxing. Its dependency cooldown policy can block newly released packages from being installed immediately, reducing exposure to fast-moving attacks. When installs are allowed, sandboxing helps limit the blast radius of suspicious or compromised packages.\n\n**Affected packages include** ([full list in appendix](#appendix-list-of-compromised-packages))**:**\n\n`@tanstack/react-router`\n\n: Routing library for React with 3M+ weekly npm downloads`@mistralai/mistralai`\n\n: Official Mistral AI JavaScript/TypeScript SDK`@opensearch-project/opensearch`\n\n: Official OpenSearch JavaScript client`@uipath/robot`\n\n: UiPath’s RPA automation runtime for enterprise workflows`@tanstack/vue-router`\n\n: TanStack’s routing library for Vue applications\n\n[StepSecurity](https://www.stepsecurity.io/blog/mini-shai-hulud-is-back-a-self-spreading-supply-chain-attack-hits-the-npm-ecosystem) and [Socket Security](https://socket.dev/blog/tanstack-npm-packages-compromised-mini-shai-hulud-supply-chain-attack) are tracking this attack as “mini-shai-hulud.”\n\n**Update (2026-05-12, ~03:05 UTC):** The campaign expanded beyond npm. The attacker compromised two PyPI packages as part of the same attack:\n\n`mistralai==2.4.6`\n\n: Malicious version of the official Mistral AI Python SDK. The legitimate latest version before the attack was`2.4.5`\n\n(published May 7). No`v2.4.6`\n\ntag exists in[mistralai/client-python](https://github.com/mistralai/client-python). PyPI has quarantined the entire`mistralai`\n\nproject.`guardrails-ai==0.10.1`\n\n: Malicious version of the Guardrails AI validation framework. PyPI has quarantined the entire`guardrails-ai`\n\nproject.\n\nThe PyPI packages use a different payload delivery mechanism from the npm packages: on import, a Python dropper downloads `transformers.pyz`\n\nfrom the attacker-controlled domain `hxxps://git-tanstack[.]com/transformers.pyz`\n\nand executes it with `python3`\n\n. This is the same `git-tanstack[.]com`\n\ndomain named in the npm campaign’s payload. Cloudflare now marks the domain as a suspected phishing site.\n\n## What Happened\n\nSafeDep’s malware detection pipeline flagged a burst of suspicious npm package publications on the night of May 11. The scope is unusual: the attacker published malicious versions across 170 distinct packages in a single coordinated campaign, unlike the [axios compromise](/axios-npm-supply-chain-compromise) in March that targeted one high-value package. The attacker went after entire organizational scopes, compromising every package under `@tanstack`\n\n, `@squawk`\n\n, `@uipath`\n\n, `@tallyui`\n\n, and several others in bulk.\n\n## Indicators of Compromise (IoC)\n\n### npm packages\n\n**C2/Exfiltration**:`hxxp://filev2[.]getsession[.]org/file/`\n\n(Session file server)**AWS metadata probe**:`hxxp://169[.]254[.]169[.]254/latest/meta-data/iam/security-credentials/`\n\n**Vault probe**:`hxxp://127[.]0[.]0[.]1:8200`\n\n**Bun runtime download**:`hxxps://github[.]com/oven-sh/bun/releases/download/bun-v1.3.13/`\n\n**Package SHA-256**:`ce7e4199506959fd7a71b64209b2c07b9c82e53a946aa7d78298dc9249230d01`\n\n(`@mistralai/`\n\n)[[email protected]](/cdn-cgi/l/email-protection)**Malicious GitHub commit**:`tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c`\n\n(payload host for`@tanstack/setup`\n\n)**Dropped files**:`.claude/settings.json`\n\n,`.claude/setup.mjs`\n\n,`.vscode/tasks.json`\n\n,`.vscode/setup.mjs`\n\n,`.claude/router_runtime.js`\n\n**GitHub API abuse**:`createCommitOnBranch`\n\nGraphQL mutation to push poisoned configs**Token patterns scanned**:`ghp_*`\n\n,`gho_*`\n\n,`ghs_*`\n\n,`npm_*`\n\n**PyPI secondary C2**:`hxxps://git-tanstack[.]com/transformers[.]pyz`\n\n(Cloudflare-proxied, registered May 9, 2026)**PyPI payload staging**:`/tmp/transformers.pyz`\n\n### PyPI packages (Update 2026-05-12)\n\n**Malicious packages**:`mistralai==2.4.6`\n\n,`guardrails-ai==0.10.1`\n\n**PyPI project status**: both projects quarantined; no files accessible** Payload download domain**:`hxxps://git-tanstack[.]com/transformers.pyz`\n\n(Cloudflare-flagged as phishing)**Payload written to disk**:`/tmp/transformers.pyz`\n\n**Execution command**:`python3 /tmp/transformers.pyz`\n\n(no integrity verification)**Trigger**: on`import`\n\n, not on`pip install`\n\n(sandboxed install environments will not catch this)\n\n## High-Profile Targets\n\n### TanStack (42 packages, 84 versions)\n\nThe TanStack ecosystem took the largest hit by package count among well-known projects. The attacker published malicious versions of every router-related package: `@tanstack/react-router`\n\n, `@tanstack/vue-router`\n\n, `@tanstack/solid-router`\n\n, along with their devtools, SSR query plugins, start frameworks, and build tooling. Two versions per package.\n\nTanStack Router powers applications across React, Vue, and Solid. Any project that pulled these versions during the attack window ran the malicious preinstall hook.\n\n### Mistral AI (3 packages, 9 versions)\n\nThe attacker compromised all three Mistral AI SDK packages:\n\n`@mistralai/mistralai`\n\n(core SDK)`@mistralai/mistralai-azure`\n\n(Azure integration)`@mistralai/mistralai-gcp`\n\n(GCP integration)\n\nThree malicious versions per package.\n\n### UiPath (65 packages, 65 versions)\n\nThe entire `@uipath`\n\nnpm scope was hit with a single compromised version per package. The affected packages span UiPath’s automation platform: agent SDKs, orchestrator tools, RPA tooling, solution packagers, and integration services.\n\n### Other Notable Targets\n\n**OpenSearch**(`@opensearch-project/opensearch`\n\n): The official OpenSearch JavaScript client with 1.3M weekly downloads, hit across 4 versions (3.5.3, 3.6.2, 3.7.0, 3.8.0)**Guardrails AI**(\n\non PyPI): Python AI guardrails framework. Uses a different loader: downloads[[email protected]](/cdn-cgi/l/email-protection)`transformers.pyz`\n\nfrom`hxxps://git-tanstack[.]com`\n\nand runs it with`python3`\n\n. The domain displayed a taunting message signed “TeamPCP”\n\n## Attack Pattern\n\nSeveral patterns stand out across the compromised packages:\n\n**Bulk scope targeting.** The attacker published across entire npm scopes rather than cherry-picking individual packages. The `@squawk`\n\nscope had 5 malicious versions per package across all 20 packages. `@tallyui`\n\nhad 3 versions each across 10 packages.\n\n**Version count variation.** TanStack packages received 2 versions each. `@beproduct/nestjs-auth`\n\nreceived 18 versions (0.1.2 through 0.1.19). `@uipath`\n\npackages received exactly 1 version each. This variation suggests the attacker may have used different strategies per target, or adjusted based on access constraints.\n\n**Concentrated timeline.** The attacker published all 401 versions within a five-hour window on May 11, suggesting automated tooling rather than manual work.\n\n**Two trigger mechanisms.** The Mistral AI packages use a `preinstall`\n\nhook: the attacker stripped legitimate build scripts and replaced them with `node setup.mjs`\n\n, which downloads Bun and runs the payload. The TanStack packages use a stealthier approach: an `optionalDependency`\n\npointing to a malicious commit in the real `tanstack/router`\n\nGitHub repository, whose `prepare`\n\nscript runs the payload via Bun. Both paths deliver the same obfuscated credential-stealing payload.\n\n**Multi-target credential harvesting.** The payload carries a modular credential stealing framework with dedicated providers for AWS IAM, HashiCorp Vault, GitHub tokens (`ghp_`\n\n, `gho_`\n\n, `ghs_`\n\n), npm publish tokens, and GitHub Actions OIDC tokens. The breadth of credential targets suggests the attacker is optimizing for lateral movement across cloud and CI/CD infrastructure.\n\n**Exfiltration over Session protocol.** The payload sends stolen credentials through the Session onion-routed messenger network instead of a traditional C2 domain. Defenders cannot take down a decentralized swarm the way they can seize a domain.\n\n**IDE and AI agent poisoning for propagation.** The payload uses stolen GitHub tokens to commit poisoned configuration files (`.claude/settings.json`\n\n, `.vscode/tasks.json`\n\n) into victim repositories via GitHub’s GraphQL API. Other developers who clone or pull these repositories inherit the malicious configurations. The attacker designed this as a self-spreading vector that targets Claude Code and VS Code users.\n\n**Shared payload template.** The Mistral AI package references its payload as `tanstack_runner.js`\n\n, a naming artifact from the TanStack packages. The `tanstack_`\n\nprefix in a Mistral AI package points to a single payload template reused across the campaign, with incomplete per-target customization.\n\n## Technical Analysis\n\nWe examined two compromised packages from different scopes to verify that the campaign uses a shared payload. The Mistral AI and TanStack packages use different trigger mechanisms but drop the same credential-stealing, C2-capable payload.\n\n### Mistral AI: @mistralai/[[email protected]](/cdn-cgi/l/email-protection)\n\n#### Package Diff: 2.2.1 vs 2.2.2\n\nThe compromised tarball is more than double the size of the legitimate release (1.9MB vs 873KB). Diffing the file trees reveals two new files and a rewritten `scripts`\n\nblock in `package.json`\n\n:\n\nThe attacker replaced all legitimate build scripts with a single `preinstall`\n\nhook and added two files:\n\n`setup.mjs`\n\n: A downloader/loader that bootstraps the attack`router_init.js`\n\n: A 2.2MB heavily obfuscated payload (single line, hex variable obfuscation)\n\nThe attacker did not modify any existing SDK source files. The attack is additive only.\n\n#### Execution Trigger: setup.mjs\n\nThe `preinstall`\n\nhook runs `setup.mjs`\n\n, which downloads a platform-specific [Bun](https://bun.sh) runtime binary from GitHub releases (`bun-v1.3.13`\n\n) and uses it to execute the obfuscated payload:\n\nThe loader supports Linux (x64, arm64, musl), macOS (x64, arm64), and Windows (x64, arm64). It detects musl-based systems (Alpine) for correct binary selection. If Bun is already installed on the system, it skips the download and uses the local copy.\n\nThe `setup.mjs`\n\nreferences the payload as `tanstack_runner.js`\n\n, but the actual file in the package is `router_init.js`\n\n. This naming mismatch means the Mistral preinstall hook fails at runtime. The `tanstack_`\n\nprefix in a Mistral AI package confirms the attacker reused a template built for the TanStack packages without updating the filename constant.\n\n### TanStack: @tanstack/[[email protected]](/cdn-cgi/l/email-protection)\n\nThe TanStack variant uses a different, more subtle trigger mechanism. Diffing `@tanstack/`\n\n(legitimate) against [[email protected]](/cdn-cgi/l/email-protection)`1.169.5`\n\n(compromised) shows the attacker left the `scripts`\n\nblock untouched and instead injected a single entry into `optionalDependencies`\n\n:\n\nNo `setup.mjs`\n\nexists in the TanStack tarball. The attack does not modify `scripts`\n\nat all. Instead, `@tanstack/setup`\n\nresolves to a malicious commit in the `tanstack/router`\n\nGitHub repository.\n\n**Note:** GitHub has since removed this commit. The commands above will return 404. Our analysis was performed before the cleanup.\n\nThat commit contained two files:\n\nThe `package.json`\n\nat that commit:\n\nnpm resolves the GitHub dependency by cloning the commit and running the `prepare`\n\nscript, which executes the payload via Bun. The `&& exit 1`\n\nforces the `prepare`\n\nstep to fail after execution, suppressing any further post-install output that might alert the developer.\n\nThis trigger is harder to spot than the Mistral variant. A reviewer scanning `package.json`\n\nsees no modified `scripts`\n\nblock. The malicious entry hides in `optionalDependencies`\n\nand points to a real GitHub repository (`tanstack/router`\n\n), not a suspicious external URL. The attacker had write access to the TanStack GitHub repository to push this commit, indicating compromised GitHub credentials in addition to npm publish tokens.\n\nThe npm tarball also contains `router_init.js`\n\n(2,341,681 bytes), a slightly larger copy of the same obfuscated payload. Both the GitHub-hosted `tanstack_runner.js`\n\nand the tarball’s `router_init.js`\n\ncontain identical malicious functionality: 396 `beautify()`\n\nencrypted string calls, the same AES decryption layer, the same credential provider class hierarchy, the same Session C2 implementation (including the `mlYTXvk...`\n\nseed node certificate fingerprint), and the same IDE poisoning file map (`.claude/settings.json`\n\n, `.vscode/tasks.json`\n\n). The hex variable names differ between the two, indicating each got a separate obfuscation pass from the same tool.\n\n### Obfuscated Payload: router_init.js\n\nThe payload is a 2.2MB single-line JavaScript file using hex variable obfuscation (`_0x12ada1`\n\n, `_0x3782`\n\n, `_0x360f`\n\n). It uses a shuffled string array with a rotation function, making static analysis difficult. Critical strings are double-encrypted: first through the hex obfuscator’s lookup table, then through AES decryption via a `w8()`\n\nfunction that uses `createDecipheriv`\n\nand Bun’s `gunzipSync`\n\n.\n\nThe payload contains a modular credential stealing framework with dedicated provider classes, all extending a base class `gQ`\n\n:\n\n| Class | Target | Credentials Harvested |\n|---|---|---|\n`NK` | AWS | `AWS_ACCESS_KEY_ID` , `AWS_SECRET_ACCESS_KEY` , IAM instance credentials via `169.254.169.254` |\n`ZK` | HashiCorp Vault | `VAULT_TOKEN` , `VAULT_AUTH_TOKEN` (default: `http://127.0.0.1:8200` ) |\n`MK` | GitHub Actions Runner | `ghp_*` , `gho_*` , `ghs_*` tokens, `ACTIONS_ID_TOKEN` |\n`JK` | GitHub Actions (CI) | `ghp_*` , `gho_*` tokens, `npm_*` tokens |\n`FK` | Secrets Manager | `ghp_*` , `gho_*` , `npm_*` tokens |\n`UK` | Secrets Manager | `npm_*` tokens |\n`DK` / `OK` | Miscellaneous | `ghp_*` , `gho_*` , `npm_*` tokens |\n\nToken patterns matched by the credential scanner:\n\n### Exfiltration via Session Protocol\n\nThe payload exfiltrates stolen credentials through the [Session](https://getsession.org) messaging protocol, an onion-routed encrypted messenger built on the Oxen network. It embeds a full Session client implementation, not a simple HTTP call to a C2 domain.\n\nThe payload bootstraps by connecting to Session’s seed nodes with pinned TLS certificates issued by the Oxen Privacy Tech Foundation:\n\nAfter retrieving the snode list, the payload resolves the target swarm for the attacker’s Session ID and routes encrypted messages through selected snodes:\n\nLarger data blobs (file uploads) go through Session’s centralized file server at `hxxp://filev2[.]getsession[.]org/file/`\n\n:\n\nThe payload uses `ed25519`\n\nand `x25519`\n\nkey pairs for Session’s end-to-end encryption. There are no fixed C2 URLs to block: message routing happens through the Session swarm network, where snode addresses are resolved at runtime. The only static infrastructure is the seed node bootstrap and the file upload server.\n\n### IDE and AI Agent Poisoning\n\nThe payload contains a self-replicating mechanism that commits malicious configuration files into victim repositories. This section traces the full chain from file map to GitHub commit.\n\n#### File Map\n\nThe payload defines a map of files to drop into target repositories:\n\n`FO`\n\n, `DO`\n\n, and `h9`\n\nare double-encrypted strings decoded at runtime through `w8(beautify(...), key)`\n\n, the same AES + gunzip pipeline used throughout the payload. The `.claude/setup.mjs`\n\nand `.vscode/setup.mjs`\n\nshare the same encrypted blob (`h9`\n\n).\n\nThe `.claude/router_runtime.js`\n\nentry does not use an encrypted string. Instead, `{ sourcePath: Bun.main }`\n\ntells the file processor (`yO`\n\nfunction) to read the currently executing script, base64-encode it, and include it in the commit. `Bun.main`\n\nresolves to the absolute path of `router_init.js`\n\n. The attacker commits the full 2.2MB obfuscated payload into the victim’s repository, ensuring the next stage of the chain has the complete malware available locally.\n\n#### Target Repository and Branch Selection\n\nThe payload reads `process.env.GITHUB_REPOSITORY`\n\n(set by GitHub Actions) and splits it into owner/repo:\n\nThe branch lister (`p6`\n\nclass) queries up to 50 branches via GitHub’s GraphQL API, then filters out branches matching an exclusion list (`s3`\n\n). The exclusion list contains four encrypted patterns, likely `main`\n\n, `master`\n\n, `develop`\n\n, and `release`\n\n. The payload targets feature and topic branches, where a new commit is less likely to trigger review and more likely to be merged into the main branch.\n\n#### Commit Execution\n\nThe payload commits poisoned files using GitHub’s `createCommitOnBranch`\n\nGraphQL mutation, batching two branch commits per API call:\n\nFor multiple branches, `xO()`\n\ngenerates a batched mutation with indexed inputs (`$input0`\n\n, `$input1`\n\n, etc.), processing two branches per request (`KS = 0x2`\n\n). Each commit includes an encrypted headline (`GS`\n\n) and a `Co-authored-by`\n\ntrailer generated from the `qS`\n\nauthor list (encrypted name and email). The co-author line makes the commit appear collaborative rather than anomalous.\n\n#### Propagation Chain\n\nThe dropped files create a self-sustaining infection loop:\n\n`.claude/settings.json`\n\nand`.vscode/tasks.json`\n\nconfigure the IDE or AI agent to execute`.claude/setup.mjs`\n\nor`.vscode/setup.mjs`\n\non project load`setup.mjs`\n\n(`h9`\n\n) runs`router_runtime.js`\n\n, which is the full payload- The payload harvests credentials from the new victim environment and repeats the cycle\n\nAny developer who clones or pulls a poisoned branch gets the malicious IDE configuration. Opening the project in VS Code or running Claude Code triggers the payload without any explicit action from the developer.\n\n#### Secondary GitHub Channels\n\nThe payload also uses GitHub’s REST API for two additional purposes:\n\n**Commit search as C2**: The`MM`\n\nfunction queries`api.github.com/search/commits`\n\nfor a specific marker (`b9`\n\n, encrypted). When matching commits are found, the payload extracts base64-encoded data from the commit messages, decodes it, and acts on the instructions. This turns GitHub’s commit history into a command-and-control channel.**Data exfiltration via repository**: The payload uploads stolen credentials to a GitHub repository under`contents/results/`\n\nusing the REST API, with retry logic (up to 5 attempts with exponential backoff). This provides an exfiltration channel that operates entirely within GitHub’s infrastructure, alongside the Session messenger channel.\n\n### PyPI Packages: mistralai 2.4.6 and guardrails-ai 0.10.1 (Update 2026-05-12)\n\nThe attacker crossed from npm into PyPI and compromised two packages. The exact publication timestamps are unavailable because PyPI quarantined both projects before we could query the metadata.\n\n#### Cross-Ecosystem Attack Chain\n\nThe attacker published `mistralai==2.4.6`\n\nand `guardrails-ai==0.10.1`\n\nto PyPI without committing to or triggering either package’s GitHub Actions release workflow. The credential source for the PyPI publishes is unknown. The npm payload steals npm tokens and GitHub tokens but does not target `~/.pypirc`\n\nor PyPI credentials. The attacker may have obtained PyPI credentials through a separate channel or through environment variables on compromised CI runners.\n\nNo commits landed in [mistralai/client-python](https://github.com/mistralai/client-python) on May 11, and no `v2.4.6`\n\ntag exists in the repository. The legitimate latest version before the attack was `2.4.5`\n\n, published May 7. Mistral AI never released version `2.4.6`\n\n.\n\n#### PyPI Payload Delivery: transformers.pyz\n\nThe PyPI packages use a different delivery mechanism from the npm packages. Instead of the `preinstall`\n\nhook and bundled `router_init.js`\n\n, the malicious Python packages inject code into the package’s `__init__.py`\n\nthat runs on every `import`\n\n.\n\nWe recovered `guardrails-ai==0.10.1`\n\nfrom a PyPI mirror before the quarantine propagated. Diffing `__init__.py`\n\nagainst the legitimate `0.10.0`\n\nshows 15 lines appended after the `__all__`\n\nexport list, with no other files modified across the entire wheel:\n\nNo obfuscation. The C2 URL, staging path, and execution command are all plaintext. The `sys.platform`\n\ncheck gates execution to Linux, so macOS and Windows installs carry the trojanized code but the dropper does not fire.\n\nPyPI and all mirrors removed the `mistralai==2.4.6`\n\nsdist before we could recover it. Based on the shared `git-tanstack[.]com`\n\ninfrastructure, it uses the same `__init__.py`\n\ninjection.\n\nThe `.pyz`\n\nextension indicates a Python zipapp, a self-contained Python archive the interpreter can execute. We did not recover the contents of `transformers.pyz`\n\nbefore `git-tanstack.com`\n\nblocked access. The domain is the same attacker-controlled infrastructure referenced in the npm payload’s deobfuscated strings. Cloudflare has flagged `git-tanstack.com`\n\nas a suspected phishing site.\n\n#### Why import-time Triggering Matters\n\nPyPI’s sandboxed install environment (`pip download`\n\n, `pip wheel`\n\n) does not execute package code, unlike npm’s `preinstall`\n\n/`postinstall`\n\nhooks. The `__init__.py`\n\ntrigger fires only when a developer or running application calls `import mistralai`\n\nor `import guardrails`\n\n. This means:\n\n- Static analysis of the sdist or wheel may show the dropper code, but automated sandbox installs that don’t exercise the package API will not observe the payload’s network activity\n- Any application that imported\n`mistralai`\n\nor`guardrails`\n\nduring the attack window should be treated as potentially compromised, regardless of whether`pip install`\n\nran in a sandboxed environment\n\n## Broader Context\n\nSupply chain campaigns in 2026 keep escalating. The [axios compromise](/axios-npm-supply-chain-compromise) in March targeted a single high-value package. This campaign cast a wide net across hundreds of packages at once, and crossed from npm into PyPI within hours. Different tactics, same root cause: a compromised publishing credential grants unrestricted access to publish new versions.\n\nThe inclusion of AI/ML packages (Mistral AI SDK on both npm and PyPI, guardrails-ai) alongside web framework packages (TanStack) and enterprise automation tooling (UiPath) suggests the attacker is targeting the broadest possible developer population rather than a specific technology vertical.\n\nWe will continue to update this post as more details emerge from the ongoing investigation.\n\n## What To Do\n\n### npm\n\nIf your project depends on any of the packages listed in the appendix below, check your lockfile for the specific compromised versions:\n\nPin your dependencies to known-good versions and regenerate lockfiles after confirming the compromised versions have been removed from the registries.\n\n### PyPI\n\nCheck whether `mistralai==2.4.6`\n\nor `guardrails-ai==0.10.1`\n\nappear in any lockfile or installed environment:\n\nIf either shows version `2.4.6`\n\n(mistralai) or `0.10.1`\n\n(guardrails-ai), treat the environment as compromised. The safe version of `mistralai`\n\nis `2.4.5`\n\nor earlier. For `guardrails-ai`\n\n, use `0.10.0`\n\nor earlier.\n\nAlso check for the payload artifact on disk:\n\nIf this file exists, the payload ran. Rotate any credentials that were present in the environment at the time of `import`\n\n.\n\n### If Any CI/CD Runner Was Exposed\n\nIf a CI/CD runner installed or ran any of the compromised npm packages and had PyPI publishing credentials available (via `~/.pypirc`\n\n, `PYPI_TOKEN`\n\n, or `PYPI_PASSWORD`\n\n), rotate those credentials now. Treat any PyPI token that was present in an environment that ran one of the compromised npm packages as stolen.\n\nSafeDep [ vet](https://github.com/safedep/vet) can scan your dependency tree against known malicious package databases:\n\n## Appendix: List of Compromised Packages\n\n### PyPI packages (Update 2026-05-12)\n\n| Package | Compromised Version | Legitimate Latest | PyPI Status | |\n|---|---|---|---|---|\n| 1 | mistralai | 2.4.6 | 2.4.5 | Quarantined |\n| 2 | guardrails-ai | 0.10.1 | 0.10.0 | Quarantined |\n| No matching rows |\n\n172 packages across npm and PyPI, 404 compromised versions, grouped by scope and package name.\n\n`@tanstack`\n\n(npm)\n\n| Package | Compromised Versions | |\n|---|---|---|\n| 1 | @tanstack/arktype-adapter | 1.166.12, 1.166.15 |\n| 2 | @tanstack/eslint-plugin-router | 1.161.9, 1.161.12 |\n| 3 | @tanstack/eslint-plugin-start | 0.0.4, 0.0.7 |\n| 4 | @tanstack/history | 1.161.9, 1.161.12 |\n| 5 | @tanstack/nitro-v2-vite-plugin | 1.154.12, 1.154.15 |\n| 6 | @tanstack/react-router | 1.169.5, 1.169.8 |\n| 7 | @tanstack/react-router-devtools | 1.166.16, 1.166.19 |\n| 8 | @tanstack/react-router-ssr-query | 1.166.15, 1.166.18 |\n| 9 | @tanstack/react-start | 1.167.68, 1.167.71 |\n| 10 | @tanstack/react-start-client | 1.166.51, 1.166.54 |\n| 11 | @tanstack/react-start-rsc | 0.0.47, 0.0.50 |\n| 12 | @tanstack/react-start-server | 1.166.55, 1.166.58 |\n| 13 | @tanstack/router-cli | 1.166.46, 1.166.49 |\n| 14 | @tanstack/router-core | 1.169.5, 1.169.8 |\n| 15 | @tanstack/router-devtools | 1.166.16, 1.166.19 |\n| 16 | @tanstack/router-devtools-core | 1.167.6, 1.167.9 |\n| 17 | @tanstack/router-generator | 1.166.45, 1.166.48 |\n| 18 | @tanstack/router-plugin | 1.167.38, 1.167.41 |\n| 19 | @tanstack/router-ssr-query-core | 1.168.3, 1.168.6 |\n| 20 | @tanstack/router-utils | 1.161.11, 1.161.14 |\n| 21 | @tanstack/router-vite-plugin | 1.166.53, 1.166.56 |\n| 22 | @tanstack/solid-router | 1.169.5, 1.169.8 |\n| 23 | @tanstack/solid-router-devtools | 1.166.16, 1.166.19 |\n| 24 | @tanstack/solid-router-ssr-query | 1.166.15, 1.166.18 |\n| 25 | @tanstack/solid-start | 1.167.65, 1.167.68 |\n| 26 | @tanstack/solid-start-client | 1.166.50, 1.166.53 |\n| 27 | @tanstack/solid-start-server | 1.166.54, 1.166.57 |\n| 28 | @tanstack/start-client-core | 1.168.5, 1.168.8 |\n| 29 | @tanstack/start-fn-stubs | 1.161.9, 1.161.12 |\n| 30 | @tanstack/start-plugin-core | 1.169.23, 1.169.26 |\n| 31 | @tanstack/start-server-core | 1.167.33, 1.167.36 |\n| 32 | @tanstack/start-static-server-functions | 1.166.44, 1.166.47 |\n| 33 | @tanstack/start-storage-context | 1.166.38, 1.166.41 |\n| 34 | @tanstack/valibot-adapter | 1.166.12, 1.166.15 |\n| 35 | @tanstack/virtual-file-routes | 1.161.10, 1.161.13 |\n| 36 | @tanstack/vue-router | 1.169.5, 1.169.8 |\n| 37 | @tanstack/vue-router-devtools | 1.166.16, 1.166.19 |\n| 38 | @tanstack/vue-router-ssr-query | 1.166.15, 1.166.18 |\n| 39 | @tanstack/vue-start | 1.167.61, 1.167.64 |\n| 40 | @tanstack/vue-start-client | 1.166.46, 1.166.49 |\n| 41 | @tanstack/vue-start-server | 1.166.50, 1.166.53 |\n| 42 | @tanstack/zod-adapter | 1.166.12, 1.166.15 |\n| No matching rows |\n\n`@mistralai`\n\n(npm)\n\n| Package | Compromised Versions | |\n|---|---|---|\n| 1 | @mistralai/mistralai | 2.2.2, 2.2.3, 2.2.4 |\n| 2 | @mistralai/mistralai-azure | 1.7.1, 1.7.2, 1.7.3 |\n| 3 | @mistralai/mistralai-gcp | 1.7.1, 1.7.2, 1.7.3 |\n| No matching rows |\n\n`@uipath`\n\n(npm)\n\n| Package | Compromised Version | |\n|---|---|---|\n| 1 | @uipath/access-policy-sdk | 0.3.1 |\n| 2 | @uipath/access-policy-tool | 0.3.1 |\n| 3 | @uipath/admin-tool | 0.1.1 |\n| 4 | @uipath/agent-sdk | 1.0.2 |\n| 5 | @uipath/agent-tool | 1.0.1 |\n| 6 | @uipath/agent.sdk | 0.0.18 |\n| 7 | @uipath/aops-policy-tool | 0.3.1 |\n| 8 | @uipath/ap-chat | 1.5.7 |\n| 9 | @uipath/api-workflow-tool | 1.0.1 |\n| 10 | @uipath/apollo-core | 5.9.2 |\n| 11 | @uipath/apollo-react | 4.24.5 |\n| 12 | @uipath/apollo-wind | 2.16.2 |\n| 13 | @uipath/auth | 1.0.1 |\n| 14 | @uipath/case-tool | 1.0.1 |\n| 15 | @uipath/cli | 1.0.1 |\n| 16 | @uipath/codedagent-tool | 1.0.1 |\n| 17 | @uipath/codedagents-tool | 0.1.12 |\n| 18 | @uipath/codedapp-tool | 1.0.1 |\n| 19 | @uipath/common | 1.0.1 |\n| 20 | @uipath/context-grounding-tool | 0.1.1 |\n| 21 | @uipath/data-fabric-tool | 1.0.2 |\n| 22 | @uipath/docsai-tool | 1.0.1 |\n| 23 | @uipath/filesystem | 1.0.1 |\n| 24 | @uipath/flow-tool | 1.0.2 |\n| 25 | @uipath/functions-tool | 1.0.1 |\n| 26 | @uipath/gov-tool | 0.3.1 |\n| 27 | @uipath/identity-tool | 0.1.1 |\n| 28 | @uipath/insights-sdk | 1.0.1 |\n| 29 | @uipath/insights-tool | 1.0.1 |\n| 30 | @uipath/integrationservice-sdk | 1.0.2 |\n| 31 | @uipath/integrationservice-tool | 1.0.2 |\n| 32 | @uipath/llmgw-tool | 1.0.1 |\n| 33 | @uipath/maestro-sdk | 1.0.1 |\n| 34 | @uipath/maestro-tool | 1.0.1 |\n| 35 | @uipath/orchestrator-tool | 1.0.1 |\n| 36 | @uipath/packager-tool-apiworkflow | 0.0.19 |\n| 37 | @uipath/packager-tool-bpmn | 0.0.9 |\n| 38 | @uipath/packager-tool-case | 0.0.9 |\n| 39 | @uipath/packager-tool-connector | 0.0.19 |\n| 40 | @uipath/packager-tool-flow | 0.0.19 |\n| 41 | @uipath/packager-tool-functions | 0.1.1 |\n| 42 | @uipath/packager-tool-webapp | 1.0.6 |\n| 43 | @uipath/packager-tool-workflowcompiler | 0.0.16 |\n| 44 | @uipath/packager-tool-workflowcompiler-browser | 0.0.34 |\n| 45 | @uipath/platform-tool | 1.0.1 |\n| 46 | @uipath/project-packager | 1.1.16 |\n| 47 | @uipath/resource-tool | 1.0.1 |\n| 48 | @uipath/resourcecatalog-tool | 0.1.1 |\n| 49 | @uipath/resources-tool | 0.1.11 |\n| 50 | @uipath/robot | 1.3.4 |\n| 51 | @uipath/rpa-legacy-tool | 1.0.1 |\n| 52 | @uipath/rpa-tool | 0.9.5 |\n| 53 | @uipath/solution-packager | 0.0.35 |\n| 54 | @uipath/solution-tool | 1.0.1 |\n| 55 | @uipath/solutionpackager-sdk | 1.0.11 |\n| 56 | @uipath/solutionpackager-tool-core | 0.0.34 |\n| 57 | @uipath/tasks-tool | 1.0.1 |\n| 58 | @uipath/telemetry | 0.0.7 |\n| 59 | @uipath/test-manager-tool | 1.0.2 |\n| 60 | @uipath/tool-workflowcompiler | 0.0.12 |\n| 61 | @uipath/traces-tool | 1.0.1 |\n| 62 | @uipath/ui-widgets-multi-file-upload | 1.0.1 |\n| 63 | @uipath/uipath-python-bridge | 1.0.1 |\n| 64 | @uipath/vertical-solutions-tool | 1.0.1 |\n| 65 | @uipath/vss | 0.1.6 |\n| 66 | @uipath/widget.sdk | 1.2.3 |\n| No matching rows |\n\n`@squawk`\n\n(npm)\n\n| Package | Compromised Versions | |\n|---|---|---|\n| 1 | @squawk/airport-data | 0.7.4, 0.7.5, 0.7.6, 0.7.7, 0.7.8 |\n| 2 | @squawk/airports | 0.6.2, 0.6.3, 0.6.4, 0.6.5, 0.6.6 |\n| 3 | @squawk/airspace | 0.8.1, 0.8.2, 0.8.3, 0.8.4, 0.8.5 |\n| 4 | @squawk/airspace-data | 0.5.3, 0.5.4, 0.5.5, 0.5.6, 0.5.7 |\n| 5 | @squawk/airway-data | 0.5.4, 0.5.5, 0.5.6, 0.5.7, 0.5.8 |\n| 6 | @squawk/airways | 0.4.2, 0.4.3, 0.4.4, 0.4.5, 0.4.6 |\n| 7 | @squawk/fix-data | 0.6.4, 0.6.5, 0.6.6, 0.6.7, 0.6.8 |\n| 8 | @squawk/fixes | 0.3.2, 0.3.3, 0.3.4, 0.3.5, 0.3.6 |\n| 9 | @squawk/flight-math | 0.5.4, 0.5.5, 0.5.6, 0.5.7, 0.5.8 |\n| 10 | @squawk/flightplan | 0.5.2, 0.5.3, 0.5.4, 0.5.5, 0.5.6 |\n| 11 | @squawk/geo | 0.4.4, 0.4.5, 0.4.6, 0.4.7, 0.4.8 |\n| 12 | @squawk/icao-registry | 0.5.2, 0.5.3, 0.5.4, 0.5.5, 0.5.6 |\n| 13 | @squawk/icao-registry-data | 0.8.4, 0.8.5, 0.8.6, 0.8.7, 0.8.8 |\n| 14 | @squawk/mcp | 0.9.1, 0.9.2, 0.9.3, 0.9.4, 0.9.5 |\n| 15 | @squawk/navaid-data | 0.6.4, 0.6.5, 0.6.6, 0.6.7, 0.6.8 |\n| 16 | @squawk/navaids | 0.4.2, 0.4.3, 0.4.4, 0.4.5, 0.4.6 |\n| 17 | @squawk/notams | 0.3.6, 0.3.7, 0.3.8, 0.3.9, 0.3.10 |\n| 18 | @squawk/procedure-data | 0.7.3, 0.7.4, 0.7.5, 0.7.6, 0.7.7 |\n| 19 | @squawk/procedures | 0.5.2, 0.5.3, 0.5.4, 0.5.5, 0.5.6 |\n| 20 | @squawk/types | 0.8.1, 0.8.2, 0.8.3, 0.8.4, 0.8.5 |\n| 21 | @squawk/units | 0.4.3, 0.4.4, 0.4.5, 0.4.6, 0.4.7 |\n| 22 | @squawk/weather | 0.5.6, 0.5.7, 0.5.8, 0.5.9, 0.5.10 |\n| No matching rows |\n\n`@tallyui`\n\n(npm)\n\n| Package | Compromised Versions | |\n|---|---|---|\n| 1 | @tallyui/components | 1.0.1, 1.0.2, 1.0.3 |\n| 2 | @tallyui/connector-medusa | 1.0.1, 1.0.2, 1.0.3 |\n| 3 | @tallyui/connector-shopify | 1.0.1, 1.0.2, 1.0.3 |\n| 4 | @tallyui/connector-vendure | 1.0.1, 1.0.2, 1.0.3 |\n| 5 | @tallyui/connector-woocommerce | 1.0.1, 1.0.2, 1.0.3 |\n| 6 | @tallyui/core | 0.2.1, 0.2.2, 0.2.3 |\n| 7 | @tallyui/database | 1.0.1, 1.0.2, 1.0.3 |\n| 8 | @tallyui/pos | 0.1.1, 0.1.2, 0.1.3 |\n| 9 | @tallyui/storage-sqlite | 0.2.1, 0.2.2, 0.2.3 |\n| 10 | @tallyui/theme | 0.2.1, 0.2.2, 0.2.3 |\n| No matching rows |\n\n`@beproduct`\n\n(npm)\n\n| Package | Compromised Versions | |\n|---|---|---|\n| 1 | @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 |\n| No matching rows |\n\n`@draftauth`\n\n/ `@draftlab`\n\n(npm)\n\n| Package | Compromised Versions | |\n|---|---|---|\n| 1 | @draftauth/client | 0.2.1, 0.2.2 |\n| 2 | @draftauth/core | 0.13.1, 0.13.2 |\n| 3 | @draftlab/auth | 0.24.1, 0.24.2 |\n| 4 | @draftlab/auth-router | 0.5.1, 0.5.2 |\n| 5 | @draftlab/db | 0.16.1, 0.16.2 |\n| No matching rows |\n\n`@supersurkhet`\n\n(npm)\n\n| Package | Compromised Versions | |\n|---|---|---|\n| 1 | @supersurkhet/cli | 0.0.2, 0.0.3, 0.0.4, 0.0.5, 0.0.6, 0.0.7 |\n| 2 | @supersurkhet/sdk | 0.0.2, 0.0.3, 0.0.4, 0.0.5, 0.0.6, 0.0.7 |\n| No matching rows |\n\n`@taskflow-corp`\n\n(npm)\n\n| Package | Compromised Versions | |\n|---|---|---|\n| 1 | @taskflow-corp/cli | 0.1.24, 0.1.25, 0.1.26, 0.1.27, 0.1.28, 0.1.29 |\n| No matching rows |\n\n`@tolka`\n\n(npm)\n\n| Package | Compromised Versions | |\n|---|---|---|\n| 1 | @tolka/cli | 1.0.2, 1.0.3, 1.0.4, 1.0.5, 1.0.6 |\n| No matching rows |\n\n`@mesadev`\n\n(npm)\n\n| Package | Compromised Version | |\n|---|---|---|\n| 1 | @mesadev/rest | 0.28.3 |\n| 2 | @mesadev/saguaro | 0.4.22 |\n| 3 | @mesadev/sdk | 0.28.3 |\n| No matching rows |\n\n`@ml-toolkit-ts`\n\n(npm)\n\n| Package | Compromised Versions | |\n|---|---|---|\n| 1 | @ml-toolkit-ts/preprocessing | 1.0.2, 1.0.3 |\n| 2 | @ml-toolkit-ts/xgboost | 1.0.3, 1.0.4 |\n| No matching rows |\n\n`@dirigible-ai`\n\n(npm)\n\n| Package | Compromised Versions | |\n|---|---|---|\n| 1 | @dirigible-ai/sdk | 0.6.2, 0.6.3 |\n| No matching rows |\n\n`@opensearch-project`\n\n(npm)\n\n| Package | Compromised Versions | |\n|---|---|---|\n| 1 | @opensearch-project/opensearch | 3.5.3, 3.6.2, 3.7.0, 3.8.0 |\n| No matching rows |\n\n### Unscoped npm Packages\n\n| Package | Compromised Versions | |\n|---|---|---|\n| 1 | agentwork-cli | 0.1.4, 0.1.5 |\n| 2 | cmux-agent-mcp | 0.1.3, 0.1.4, 0.1.5, 0.1.6, 0.1.7, 0.1.8 |\n| 3 | cross-stitch | 1.1.3, 1.1.4, 1.1.5, 1.1.6, 1.1.7 |\n| 4 | git-branch-selector | 1.3.3, 1.3.4, 1.3.5, 1.3.6, 1.3.7 |\n| 5 | git-git-git | 1.0.8, 1.0.9, 1.0.10, 1.0.11, 1.0.12 |\n| 6 | ml-toolkit-ts | 1.0.4, 1.0.5 |\n| 7 | nextmove-mcp | 0.1.3, 0.1.4, 0.1.5, 0.1.6, 0.1.7 |\n| 8 | safe-action | 0.8.3, 0.8.4 |\n| 9 | ts-dna | 3.0.1, 3.0.2, 3.0.3, 3.0.4, 3.0.5 |\n| 10 | wot-api | 0.8.1, 0.8.2, 0.8.3, 0.8.4 |\n| No matching rows |\n\n### PyPI Packages\n\nThe attack expanded beyond npm into the Python Package Index (PyPI), hitting two high-profile packages. The `guardrails-ai`\n\npayload uses a different delivery mechanism: it downloads a secondary-stage payload from `hxxps://git-tanstack[.]com/transformers[.]pyz`\n\nand executes it with `python3`\n\n. The `git-tanstack[.]com`\n\ndomain displayed a message signed “With Love TeamPCP,” connecting this campaign to the group behind the [March 2026 Trivy supply chain compromise](/trivy-teampcp-supply-chain-compromise).\n\n| Package | Compromised Version | Ecosystem | |\n|---|---|---|---|\n| 1 | guardrails-ai | 0.10.1 | PyPI |\n| 2 | mistralai | 2.4.6 | PyPI |\n| No matching rows |\n\n- npm\n- pypi\n- oss\n- malware\n- supply-chain\n\n### Author\n\n#### SafeDep Team\n\nsafedep.io\n\n### Share\n\n## The Latest from SafeDep blogs\n\nFollow for the latest updates and insights on open source security & engineering\n\n[Megalodon: Mass GitHub Repo Backdooring via CI Workflows](/megalodon-mass-github-repo-backdooring-ci-workflows)\n\nOver 5,700 malicious commits were pushed to GitHub repositories on May 18, 2026, replacing GitHub Actions workflows with base64-encoded secret exfiltration payloads. The \"megalodon\" campaign targeted...\n\n[art-template npm Hijack Delivers iOS Browser Exploit Kit](/art-template-npm-supply-chain-compromise)\n\nart-template versions 4.13.3 through 4.13.6 were compromised via maintainer account takeover. The browser bundle injects scripts that deliver a full iOS exploit kit: WebAssembly type confusion, JIT...\n\n[Polymarket npm Packages Steal Crypto Wallet Keys](/malicious-polymarket-npm-crypto-wallet-drainer)\n\nNine coordinated npm packages target Polymarket traders with a social-engineered postinstall prompt that exfiltrates raw private keys to a Cloudflare Worker. The attacker published all packages...\n\n[Malicious durabletask on PyPI: Multi-Cloud Credential Stealer with Worm Capabilities](/malicious-durabletask-pypi-supply-chain-attack)\n\nThree compromised versions of the Microsoft durabletask Python SDK (1.4.1, 1.4.2, 1.4.3) were published to PyPI, each downloading a stage-2 payload that steals credentials from AWS, Azure, GCP,...\n\n## Ship Code.\n\n## Not Malware.\n\nStart free with open source tools on your machine. Scale to a unified platform for your organization.", "url": "https://wpnews.pro/news/mass-supply-chain-attack-hits-tanstack-mistral-ai-npm-and-pypi-packages", "canonical_source": "https://safedep.io/mass-npm-supply-chain-attack-tanstack-mistral", "published_at": "2026-05-12 06:00:00+00:00", "updated_at": "2026-05-19 22:30:01.800397+00:00", "lang": "en", "topics": ["cybersecurity", "open-source", "developer-tools"], "entities": ["TanStack", "Mistral AI", "UiPath", "OpenSearch", "Guardrails AI", "Package Manager Guard", "StepSecurity", "Socket Security"], "alternates": {"html": "https://wpnews.pro/news/mass-supply-chain-attack-hits-tanstack-mistral-ai-npm-and-pypi-packages", "markdown": "https://wpnews.pro/news/mass-supply-chain-attack-hits-tanstack-mistral-ai-npm-and-pypi-packages.md", "text": "https://wpnews.pro/news/mass-supply-chain-attack-hits-tanstack-mistral-ai-npm-and-pypi-packages.txt", "jsonld": "https://wpnews.pro/news/mass-supply-chain-attack-hits-tanstack-mistral-ai-npm-and-pypi-packages.jsonld"}}