Safeguard
Supply Chain Security•

GitHub Actions cache-mode, and the cache poisoning attacks behind it

GitHub added a cache-mode setting on 10 September 2026 to limit who can write to the Actions cache. Socket ties it to the TanStack npm compromise and other cache poisoning cases.

Safeguard Security Team
3 min read

On 10 September 2026 GitHub announced cache-mode, a setting that applies least privilege to the GitHub Actions cache. It is generally available on github.com for all plans. This post covers the control and the attacks it responds to, using GitHub's changelog and Socket's write up, and keeps the two apart.

What GitHub announced

From the changelog, cache-mode can be set at workflow or job level with four values:

  • read restores caches but blocks saving.
  • write restores and saves.
  • write-only saves but blocks restoring.
  • none blocks all cache access.

Low trust events such as pull_request_target default to read. Trusted events such as push default to write. Job level settings override workflow level, the cache service enforces the mode, and a reusable workflow cannot get more cache access than its caller. Declaring write or write-only on a low trust event adds a warning annotation. The changelog page I read does not include a YAML example and links to the workflow syntax documentation.

An earlier GitHub change on 26 June 2026 made cache tokens read only for untrusted triggers.

The incidents, as Socket describes them

Socket (16 September) says the motivating cases include the Ultralytics PyPI compromise in 2024, the TanStack npm compromise in May 2026, and the Cline compromise. For TanStack, Socket says an attacker chained cache poisoning with a pull_request_target workflow and published 84 malicious versions across 42 @tanstack/* packages. It calls the Cline case suspected cache poisoning triggered by a prompt injection in a GitHub issue.

The link between these incidents and the new setting is Socket's characterization, not a statement quoted from GitHub. Socket also notes that build provenance still passes on builds that restored a tampered cache, so provenance does not detect poisoning, and that cache-mode does not address untrusted checkouts, package lifecycle scripts or OIDC token minting.

What to do now

  1. List workflows that use pull_request_target or other low trust triggers and that restore or save caches.
  2. Set cache-mode: none for workflows that run AI agents or that hold publish permissions, which is what GitHub recommends for agent workflows per Socket. Check the syntax in GitHub's workflow documentation before committing.
  3. Do not set write on low trust events unless you can say why.
  4. Separate release jobs from test jobs, and have release jobs not restore caches produced by pull request builds.
  5. Review whether a past release restored a cache from an untrusted run.

How this could have been avoided

  • A read only cache for pull request workflows removes the write step of the chain.
  • Keeping publish credentials out of any workflow that restores a shared cache means a poisoned entry has nothing to steal.
  • Using environments that need approval for release, as the zod project does, stops a normal release of bad code.
  • Not combining pull_request_target with a checkout of the pull request's code removes the initial foothold.

Try it yourself

Walk through hardening a CI workflow in the CI and CD demo.

Click through it at your own pace, or open it full screen.

Quick check

Does cache-mode make provenance attestations safe to trust?

No. Socket notes that provenance still passes on a build that restored a tampered cache entry.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.