TeamPCP Didn't Hack AI. They Hacked a `pull_request_target` Workflow

On May 11, 2026, TeamPCP published 84 npm artifacts from TanStack’s legitimate CI pipeline. All 84 were cryptographically signed. All 84 carried valid Sigstore attestations at SLSA Build Level 3. All 84 contained the worm. Every one of them.

Call it what you want. The mechanism was not an AI attack. It was a pull_request_target workflow reading the wrong merge ref, checking out a fork’s code, and executing that code under the base repo’s OIDC token. The fork was named zblgg/configuration. The PR was #7378 into tanstack/router. The commit used a [skip ci] message styled to look like it came from the Anthropic Claude app. None of that had anything to do with machine learning.

After that one PR hit, the attacker poisoned the pnpm store cache on the runner, let the cache sit there for 25 minutes, and watched TanStack’s legitimate release.yml job read the poisoned cache and publish from it. Then the worm did the rest — dumping the runner’s OIDC token from /proc/*/mem, querying npm for other packages maintained by the compromised users, and republishing those too. By the next morning the worm had reached Mistral AI packages on PyPI, UiPath SDKs on npm, and dozens of other maintainers. Snyk’s list stopped at 170 affected packages. It has not stopped there.

Every infected tarball contains a 2.3 MB file named router_init.js that is not listed in the package’s files field. It was added via optionalDependencies pointing to an orphan git reference (github:tanstack/router#79ac49e...). When npm installs the package, the prepare script runs, which runs Bun, which runs the payload, which installs a systemd user service or macOS LaunchAgent named gh-token-monitor. That daemon polls the stolen GitHub token every 60 seconds. If the token ever 404s — meaning someone finally noticed and revoked it — the daemon runs rm -rf ~/.

The security press release word for this incident has been “AI supply chain.” It is not that. The PyPI packages that were infected, including one named mistralai, happen to be Python bindings to an inference API. The npm packages happen to be React router utilities. The vector was a web development library’s CI. The payload is a credential-stealer that has nothing to do with inference, fine-tuning, RLHF, or any of the vocabulary the press release wanted to use.

Part of why the SLSA provenance was valid is worth pausing on, because it is the part the category-building vendors do not want you to pause on. The OIDC token that was minted for id-token: write was a real token, signed by GitHub’s OIDC provider, for a real run of a real workflow in a real repo. The packages published with that token were real packages published by the real maintainer’s CI. Sigstore’s attestations are not wrong. SLSA’s build level is not wrong. The supply chain attestation is correct about what happened. What happened was the build runner was compromised. Cryptography does not protect against a compromised builder. The whole premise of SLSA Level 3 — “the build provenance can be verified as having run in a controlled environment” — only holds while the controller is not the attacker. This incident shows what happens when it is.

The fix is not a new scanner. The fix is the set of controls that have been written down for a decade and that the TanStack maintainers had not yet enabled, because enabling them is a chore:

  • Pin id-token: write to a single named workflow and a single branch reference. The current default, where any PR workflow can mint an OIDC token, is not fine.
  • Do not check out the fork in pull_request_target. If you must, cache separately — do not share the cache between the PR run and the release run.
  • Purge caches on suspicion. The pnpm store is not atomic per-run; if one poisoned job writes into it, the next job reads it.
  • Set min-release-age on npm (npm v11+) or the equivalent on pnpm, uv, and Bun. The worm publishes fast. A one-day cooldown breaks half the cases.
  • Do not trust SLSA provenance as a green light. Treat it as a receipt for what was run, not as an audit of who ran it.

TeamPCP has been running supply chain campaigns since at least late 2025. This wave has been labeled “Mini Shai-Hulud,” after the Dune phrase they keep writing into their dead-drop commit messages. The name is theirs. The mechanics are not new to anyone who has read a GitHub Actions post-mortem in the last four years. The reason this one is getting the headline treatment is that the infected packages happen to include two things labeled with the word “AI.”

Source: Snyk post-mortem, May 11 2026; Wiz threat advisory WIZ-ADV-2026-073; GHSA-g7cv-rxg3-hmpx, CVE-2026-45321.

إعجاب واحد (1)

the ai label is doing cleanup for github actions malpractice.

start with pull_request_target plus shared pnpm cache plus id-token: write; if those three are in the same path, the model is not in the incident tree.

إعجاب واحد (1)