ACTIONS CACHE POISONING CHECK · RUNS IN YOUR BROWSER

Can a fork PR poison your GitHub Actions cache?

Actions cache entries are scoped to the whole repository, not to a branch or a trust level. A job triggered by pull_request_target or workflow_run runs with your secrets even though a stranger's fork raised the event — and if it writes to actions/cache, that stranger controls what a later, privileged workflow may restore. This is the exact root cause of the TanStack Router incident (May 2026). Paste your workflow YAML below and this page finds both a fork-writable cache and a restore-keys fallback that can adopt a colliding entry, each with the exact fix.

Nothing is uploaded. The YAML you paste is read in this browser and never leaves your device, and this tool makes no network calls of its own.

1. Paste one or more workflow files

Copy the contents of each file under .github/workflows/ you want checked. Add more blocks for more files — nothing here reads your repository, so pasting is how it sees anything.

Paste at least one workflow file above and click Check.

Prefer a CLI, or want this in your own CI?

Same logic, zero dependencies, one file:

python3 check.py                  # scan .github/workflows under the current directory
python3 check.py /path/to/repo    # scan a specific checkout
python3 check.py --format json    # machine-readable
python3 check.py --fail-on-risk   # exit 2 if any finding exists

Get check.py from the repo — stdlib only, nothing to install, no network calls. Wire --fail-on-risk into your own CI to block a newly-added finding before it merges.

Common questions

What is GitHub Actions cache poisoning?

GitHub Actions cache entries are scoped to the repository, not to the branch or the trust level of whoever triggered the run that wrote them. If a job triggered by pull_request_target or workflow_run — which runs with the base repository's secrets even though a stranger's fork raised the event — writes to the cache, the fork controls what a later, more privileged workflow may restore. In the TanStack Router incident (May 2026), a fork PR wrote a poisoned dependency-store cache entry on every push, and the project's release pipeline later restored and executed it.

What does restore-keys have to do with it?

restore-keys is a fallback list: a miss on the exact cache key can still restore a different entry that only shares the key prefix. Independent researchers (AdnaneKhan's ActionsCacheBlasting proof-of-concept, Hive Security's cache-poisoning writeup) describe this in practice as "all keys are restore keys" — an attacker who can write any entry under a shared prefix, including from an unrelated unprivileged job, can get a privileged restore-keys fallback to adopt it on the next miss.

Does this tool fetch anything from GitHub for me?

No. It makes no network calls at all — nothing here can, because nothing here talks to a server. Paste your workflow YAML and the scan runs entirely in this page.

Does a clean scan mean my cache usage is safe?

No. This checks two specific, well-documented patterns in a single workflow file at a time. It is not a security audit and makes no claim about your repository's overall security. It does not catch the cache: input on actions/setup-node, actions/setup-python, actions/setup-java, or actions/setup-go, and it does not correlate a cache write in one workflow file with a restore in another.

Why is unscoped restore-keys flagged regardless of trigger type?

The risk lives on the restoring side, not the triggering side: a restore-keys fallback is exactly as adoptable on a push-to-main workflow as anywhere else, if anything in the repository — including an unrelated, unprivileged job — can write a cache entry under the same key prefix.

More: what is GitHub Actions cache poisoning? · how this differs from zizmor's cache-poisoning audit · where a manual read holds up and where it slips