ghtier
← Back to Organization plane incidents
OrganizationOngoing

Actions cache poisoning (Angular, TanStack)

Actions caches are shared between PR workflows and release workflows. One researcher's angular/dev-infra chain was script injection via ${{ github.head_ref }} in a pull_request_target workflow, then cache filling with a purpose-built tool. TanStack saw 84 malicious versions across 42 @tanstack/* packages from the same class of chain on 11 May 2026: a pull_request_target workflow ran a fork's code, which poisoned the pnpm store in the shared cache, and the release workflow restored it and leaked its npm OIDC token. There is no CVE for any of this; the cache is behaving exactly as designed.

Permissions abused

Fork PR write into a cache shared with release workflows

Reported by: Adnan Khan

How it unfolded

  1. 1

    A pull request opens the door

    An attacker opens an ordinary-looking PR against a workflow triggered on pull_request_target that checks out the PR's own head commit. That trigger runs with the base repository's secrets and cache access, even though the code being executed is the attacker's.

  2. 2

    The shared build cache gets poisoned

    During that run, the attacker's code writes a tampered dependency store into GitHub Actions' cache under the same key a legitimate release build would use — cache keys are derived from the lockfile hash and scoped to the whole repository, not to the branch or workflow that wrote them.

  3. 3

    A real release restores the poisoned entry

    Days or weeks later, a maintainer pushes to main and the publish workflow runs. It restores the cache entry with the matching key — the poisoned one — and installs from it, with no indication anything is wrong.

  4. 4

    The publishing token is extracted from memory

    The tampered install code executes inside the trusted release job and dumps runtime memory, recovering the OIDC token the workflow had just obtained to authenticate to the npm registry.

  5. 5

    84 malicious versions ship before detection

    Using the stolen token, the attacker publishes 84 tampered versions across 42 @tanstack/* packages — including Query, Router, and Form, each with millions of weekly downloads — before the versions are caught and yanked.

Mitigations

  • Audit every pull_request_target workflow — remove or isolate any that also check out and run the PR's own code

  • Pin actions/cache, actions/checkout, and every third-party action to a full commit SHA — not a mutable tag

  • Separate cache scopes for PR workflows and release workflows — distinct key prefixes (e.g. pr- vs release-) so a fork PR can never write into a key a release job will later restore

  • Restrict which workflows can request an OIDC publishing token — using environment protection rules

  • Disable caching entirely in release/publish workflows and install fresh every time — the cold-install cost is negligible next to the exposure

Frameworks

Ongoing. First seen May 2026. TanStack: 84 malicious versions across 42 packages (as of 11 May 2026, source). Mapping by ghtier, not yet reviewed. Threat landscape