Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.pipefort.com/llms.txt

Use this file to discover all available pages before exploring further.

FieldValue
Rule IDslsa-build-l3-cache-poisoning
SeverityHIGH
SLSA levelv1.2 Build L3
Auto-fix

What the check does

Fires when all of the following are true:
  1. The workflow triggers on pull_request_target.
  2. A job has an actions/cache@… step.
  3. That step’s key: (or restore-keys:) interpolates a PR-controlled context: github.head_ref, github.event.pull_request.head.{ref,sha,label}, or github.event.pull_request.{title,body,number}.

Why it matters

pull_request_target runs in the base branch’s privileged context with repository secrets and write tokens. If the cache key is derived from data the attacker controls (a PR’s head ref, title, etc.), the attacker can plant a cache entry that subsequent trusted base-branch builds will restore — letting them inject arbitrary files into the build, violating SLSA Build L3’s isolation guarantee.

Vulnerable example

on: pull_request_target
jobs:
  cache-deps:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/cache@<sha>
        with:
          path: ~/.npm
          key: ${{ runner.os }}-${{ github.head_ref }}     # ← PR-controlled

Safe alternatives

# Option 1: derive the key from trusted state only.
- uses: actions/cache@<sha>
  with:
    path: ~/.npm
    key: ${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}

# Option 2: move PR-specific caching to a non-elevated pull_request workflow.
on: pull_request                    # ← no secrets, no write permissions