GitHub Actions Adds Cache-Mode to Limit CI Cache Poisoning

GitHub Docs cache-mode table showing read, write, write-only and none restore and save permissions

GitHub has added cache-mode to GitHub Actions, giving a workflow or individual job an explicit ceiling for cache access. The September 10 change turns a previously implicit trust decision into four named modes—read, write, write-only, and none—and gives maintainers a practical way to stop low-trust automation from writing artifacts that a privileged job might later restore.

Why cache access is a trust boundary

The control matters because an Actions cache is not just a speed optimization. It crosses workflow runs. If a job influenced by an outside contributor can save files into a cache namespace later consumed by a release or deployment job, the cache can become a supply-chain path rather than a harmless copy of dependencies. GitHub’s documentation calls that failure class cache poisoning.

What the four modes actually permit

The new key can be set at workflow level or job level, and a job-level value overrides the workflow value. GitHub documents the matrix plainly: read permits restore but not save; write permits both; write-only permits save but not restore; and none permits neither. The runner exposes the effective choice through ACTIONS_CACHE_MODE; current actions/cache and the @actions/cache toolkit honor it.

If the key is omitted, trusted triggers default to write access while low-trust triggers default to read access. GitHub identifies pull_request_target, issue_comment, and workflow_run among events that can be influenced from outside the repository. A normal pull_request run remains separately scoped to its merge ref, so its cache cannot be restored by the base branch.

name: untrusted-analysis
on: pull_request_target
cache-mode: read
jobs:
  scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/cache/restore@v4
        with:
          path: ~/.cache/tool
          key: tool-${{ runner.os }}-${{ hashFiles('tool.lock') }}

That is a useful baseline for jobs that need a warmed cache but should never update it. A separate workflow triggered by a trusted push can maintain the same cache. If a read-only job still calls a save operation, GitHub says the save is skipped, the workflow continues, and the log receives a warning rather than a failed job.

Reusable workflows need an explicit ceiling

The less obvious detail is propagation. An explicit mode on a calling job limits the reusable workflow it invokes. If the caller sets read, a called workflow that asks for write cannot start and GitHub reports a validation error. But if the caller neither sets nor inherits a mode, the called workflow may explicitly request write even when the caller’s low-trust trigger would otherwise default to read.

That makes the caller the right place for a security boundary. Repository maintainers should search both direct jobs and uses: owner/repo/.github/workflows/... calls, then place cache-mode: read or none at the boundary exposed to issue text, fork code, or other untrusted input. write-only is specialized: it prevents a job from consuming older cache content while allowing it to publish a fresh entry, but it is not a safe default for an untrusted job.

Do not override the safe default casually

GitHub warns that explicitly setting write or write-only on a low-trust trigger restores the cache-poisoning risk the read-only default is designed to reduce. That warning aligns with independent supply-chain analysis of compromised CI workflows: cache contents should not be treated as trustworthy merely because the later consumer has stronger credentials.

The first audit question is therefore not “does this workflow use a cache?” It is “which event controls the writer, and which later job trusts what it wrote?” Use read where outside input only needs performance, none where cache state adds no value, and reserve write-capable modes for jobs whose inputs and execution path are trusted. For CI isolation beyond caches, compare the new control with TVG’s GitHub Copilot enterprise sandbox analysis; cache permissions narrow one channel, not the runner’s entire attack surface.

Sources

About TVG Editorial Team

TVG Report editorial coverage for robotics, AI, maker hardware, automation, and STEM technology.

View all posts by TVG Editorial Team →

Leave a Reply

Your email address will not be published. Required fields are marked *