May 12, 2026·7 min read·26 visits
A misconfigured GitHub Actions workflow allowed attackers to extract OIDC tokens from runner memory, resulting in the unauthorized publishing of 84 credential-stealing @tanstack npm packages.
On May 11, 2026, threat actors executed a multi-stage supply chain attack against the @tanstack ecosystem. By exploiting a pull_request_target misconfiguration in GitHub Actions, attackers poisoned build caches and extracted OIDC tokens from memory. This allowed the unauthorized publication of 84 malicious package versions containing credential-stealing malware.
CVE-2026-45321 describes a critical supply chain compromise affecting the @tanstack npm ecosystem. On May 11, 2026, threat actors successfully published 84 malicious versions across 42 discrete packages. This incident demonstrates a complex chain of exploitation utilizing CI/CD misconfigurations to achieve unauthorized package publication.
The attack surface centers on the TanStack/router repository's GitHub Actions configuration. The vulnerability class encompasses CWE-506 (Embedded Malicious Code) resulting from a broader CI/CD security failure. The impact is classified as Critical (CVSS 9.6), allowing attackers to distribute credential-harvesting malware to downstream users.
The malware functions as a self-spreading supply chain worm dubbed "Mini Shai-Hulud". It specifically targets sensitive developer credentials and cloud provider tokens upon installation. The incident highlights the inherent risks of shared execution environments in open-source continuous integration pipelines.
The root cause resides in a multi-stage exploitation of the GitHub Actions workflow environment. The primary entry point was an insecure implementation of the pull_request_target trigger within the TanStack/router repository. This specific trigger executes workflows in the context of the base repository, thereby granting the environment access to sensitive repository secrets even when the pull request originates from an untrusted fork.
The attacker leveraged this elevated execution context to perform GitHub Actions cache poisoning. By submitting a crafted pull request, the attacker injected malicious build artifacts into the shared cache infrastructure. Subsequent legitimate builds initiated by project maintainers ingested these poisoned artifacts, successfully bridging the isolation gap between fork and base execution contexts.
Following cache poisoning, the malicious artifacts executed within the trusted runner environment. The code performed runtime memory extraction by scanning the heap of the runner process. This extraction specifically targeted the OIDC JSON Web Token (JWT) used for the trusted-publisher binding between GitHub and the npm registry.
Acquisition of this OIDC token provided the attacker with transient, authenticated access to the @tanstack npm scope. Because the token grants publishing rights without requiring a persistent npm secret, the attacker immediately utilized it to publish 84 compromised package versions. This mechanism bypasses traditional static secret scanning defenses.
The malware distribution relies on dependency smuggling via an orphan commit. The malicious packages declared an optionalDependencies block pointing to a specific Git URL. This URL referenced commit 79ac49eedf774dd4b0cfa308722bc463cfe5885c within a fork of the TanStack repository.
Many standard security scanners fail to distinguish between commits in the main repository and commits existing solely in forks when utilizing global commit namespaces. This architectural quirk allowed the dependency to bypass initial static analysis checks. The injected configuration follows this structure:
"optionalDependencies": {
"@tanstack/setup": "github:tanstack/router#79ac49eedf774dd4b0cfa308722bc463cfe5885c"
}The targeted orphan commit contained a package.json file designed to trigger execution during the installation phase. It utilized a prepare script defined as "bun run tanstack_runner.js && exit 1". The intentional exit 1 forces the installation of the optional dependency to fail, prompting npm to silently discard the failed installation directory while the malicious script continues execution in the background.
Exploitation against downstream users initiates immediately upon running npm install for an affected @tanstack package. The package manager resolves the optionalDependencies and fetches the repository at the specified orphan commit. Upon extraction, npm triggers the prepare script defined in the malicious payload.
The prepare script executes tanstack_runner.js, which subsequently unpacks and triggers router_init.js. This file is a 2.3 MB heavily obfuscated JavaScript payload containing the core credential-stealing logic. The execution occurs silently in the background, decoupled from the standard installation output due to the intentional failure code.
The malware systematically scans the host file system and environment variables for high-value credentials. Targeted assets include cloud provider configurations for AWS, GCP, and Azure, alongside Kubernetes configurations located at ~/.kube/config. It also targets developer identities, extracting GitHub Personal Access Tokens (PATs), SSH keys from ~/.ssh/, and session tokens from .npmrc.
Exfiltration of the harvested data bypasses standard IP-based firewall blocking by utilizing the Session/Oxen messenger network. This network is decentralized and encrypted, obfuscating the destination of the stolen credentials. The combination of silent background execution, intentional installation failure, and decentralized exfiltration complicates both detection and incident response.
The compromise of the @tanstack ecosystem carries a critical security impact due to the framework's widespread adoption in modern web development. The installation of a single affected package version results in the total compromise of the developer's local environment or the CI/CD pipeline where the installation occurs. The CVSS v3.1 score of 9.6 reflects the remote nature, low attack complexity, and high impact on confidentiality, integrity, and availability.
Attackers gaining access to stolen AWS, GCP, Azure, and Kubernetes credentials can pivot laterally into organizational infrastructure. This facilitates secondary supply chain attacks, data breaches, and ransomware deployment. The extraction of .npmrc tokens specifically enables the malware to propagate further by publishing malicious updates to internal or external packages maintained by the victim.
The incident highlights a fundamental flaw in relying solely on OIDC tokens without strict runtime memory protections in shared runners. While OIDC eliminates persistent secrets, memory extraction proves that transient tokens remain vulnerable if the runner execution environment is compromised. This necessitates a reevaluation of threat models surrounding CI/CD pipeline isolation.
Immediate remediation requires the systematic revocation and rotation of all exposed credentials. Developers and CI/CD pipelines that executed npm install on any affected @tanstack package between May 11, 2026, and the disclosure date must assume their local secrets are compromised. This includes SSH keys, cloud provider tokens, and GitHub PATs.
Users must purge their local package manager caches to prevent re-installation of the malicious artifacts. Executing npm cache clean --force or the equivalent command for Bun or Yarn removes the cached vulnerable versions. Following cache clearance, project lockfiles should be audited for anomalous Git URL dependencies pointing to unrecognized commit hashes.
Maintainers of open-source projects must harden their GitHub Actions configurations to prevent stage one of this attack. The pull_request_target trigger must be avoided when utilizing actions/checkout on untrusted fork code unless executed within a strictly isolated environment. CI/CD pipelines must enforce the Principle of Least Privilege by restricting the id-token: write permission exclusively to deployment jobs.
To mitigate runtime memory extraction, maintainers should enforce runner-level isolation mechanisms. Restricting system calls like ptrace prevents unauthorized processes from reading the memory space of the runner process. Implementing strong execution boundaries ensures that even if arbitrary code execution is achieved, transient secrets remain protected from extraction.
Detecting the presence of the Mini Shai-Hulud malware requires analyzing both static package manifests and runtime network behavior. Static analysis tools should parse package.json and lockfiles for optionalDependencies pointing to Git URLs. A key indicator of compromise is the reference to the specific commit hash 79ac49eedf774dd4b0cfa308722bc463cfe5885c within the @tanstack namespace.
File system monitoring should flag the creation or execution of router_init.js within temporary directories or node_modules. Because the initial prepare script forces an installation failure via exit 1, the residual presence of this file strongly indicates a successful payload detonation. The file exhibits high entropy due to the obfuscation techniques applied.
Network intrusion detection systems must monitor for anomalous outbound traffic originating from CI/CD runners or developer workstations. The malware utilizes the Session/Oxen messenger network for exfiltration. Detecting connections to known Oxen service nodes or identifying the protocol signatures of this encrypted messaging system provides a high-fidelity alert for credential theft.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
@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/outer-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 | - |
| Attribute | Detail |
|---|---|
| CVE ID | CVE-2026-45321 |
| CVSS Score | 9.6 |
| CWE ID | CWE-506 |
| Attack Vector | Network |
| Exploit Status | Active |
| KEV Status | Not Listed |
The product contains code that appears to be malicious in nature, such as credential-stealing malware embedded within software dependencies.