SEC015 — release-cache-poisoning¶
Severity: warning · Category: Security
What it checks¶
Flags a job that restores a GitHub Actions cache (via actions/cache
or a setup-* action's built-in cache: input) inside a workflow
triggered by release.
Why it matters¶
Anyone with a valid GITHUB_TOKEN — for example, from an unrelated,
low-privilege PR run — can write entries into a repo's GitHub Actions
cache. If a release-triggered workflow later restores a cache keyed in
a way an attacker could predict or collide with, that poisoned entry
gets restored into a privileged release job, potentially executing
attacker-controlled code at build time or tampering with the artifact
that ends up published.
Examples¶
Flagged — a release build reuses whatever cache entry matches, without regard for who might have written it:
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f
with:
path: node_modules
key: npm-${{ hashFiles('package-lock.json') }}
- run: npm publish
Fixed — skip caching entirely for the release path, keeping the published artifact built from a clean, unrestored state:
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- run: npm ci # fresh install, no cache restore
- run: npm publish
Some caching actions support disabling restoration conditionally instead
of removing the step entirely — check the specific action's docs for an
input like enable-cache: false or lookup-only: true that can be
tied to the release trigger.
Suppressing¶
The finding is reported on the job's declaration line:
publish: # vlotpipe: ignore[SEC015]
runs-on: ubuntu-latest
Reasonable if the cache key is content-addressed in a way that makes poisoning it require also compromising the content it's keyed on (making the cache no more attacker-controllable than the source itself).