Third-party action is not pinned by commit SHA
Control: Third-party actions must be pinned by commit SHA · Config key: actionsMustBePinnedByCommitSha
📋 What is this?
A workflow step references a third-party action by a mutable ref (tag like v4 or branch like main) instead of a 40-character commit SHA.
⚠️ Impact
Tag and branch refs are mutable. The March 2025 tj-actions/changed-files compromise (CVE-2025-30066) retagged a stable version to point at malicious code that exfiltrated repo secrets from every CI run consuming the action — and there were thousands.
🔧 How to fix
Replace each uses: owner/repo@vX with uses: owner/repo@<40-char-sha> # vX.Y.Z. Use Dependabot or Renovate to bump the SHA when upstream releases.
# .github/workflows/test.yml — ❌ Mutable refs everywherejobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: tj-actions/changed-files@v45 - uses: some-third-party/action@main# .github/workflows/test.yml — ✅ Pinned by SHAjobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: tj-actions/changed-files@cc733854b1f224978ef800d29e4709d5ee2883e4 # v46.0.5 - uses: some-third-party/action@a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4 # v2.1.0
# .plumber.yaml — opt in + skip first-party actionsgithub: controls: actionsMustBePinnedByCommitSha: enabled: true trustedOwners: [actions, github]💡 Tips
- List
actionsandgithubundertrustedOwnersto skip the rule for first-party GitHub-owned actions. - Local actions (
uses: ./.github/actions/foo) are always exempt — they live in the same repo. - Pair with ISSUE-702–115 for a complete supply-chain ruleset (archived repos, impostor SHAs, stale pins, etc.).
⚙️ Configuration
This control is configured in .plumber.yaml under the github section:
github:
controls:
actionsMustBePinnedByCommitSha:
enabled: trueSee the CLI documentation for the full configuration reference.