How to Pin and Allowlist GitHub Actions in Cloud Deployment Pipelines
Retrospective: this article looks back at events from March 2025, written in 2026 with the benefit of hindsight.
The tj-actions compromise showed that referencing GitHub Actions by tag lets an attacker change your pipeline without touching your code. Here is how to pin and allowlist actions.
Step 1: Pin actions to full commit SHAs
Instead of:
uses: some-org/some-action@v4
use:
uses: some-org/some-action@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v4.1.2
A full 40-character SHA can't be moved. Keep the version comment for readability. Tools such as Dependabot and Renovate can update pinned SHAs through reviewed pull requests.
Step 2: Restrict allowed actions
In GitHub organization or enterprise settings under Actions → General → Policies:
- Allow only actions created by GitHub and verified creators, plus a specific allowlist of third-party actions.
- Optionally require actions to be pinned to a full-length commit SHA (GitHub added this policy option).
Step 3: Limit token permissions
Set the default GITHUB_TOKEN permissions to read-only at the organization level, and grant additional permissions per job only where needed:
permissions:
contents: read
Step 4: Remove stored cloud secrets
Use OIDC federation to AWS and Azure (see our guide), so pipelines have no long-lived cloud secrets to leak.
Step 5: Protect logs
Avoid printing secrets; GitHub masks known secrets, but encoded or transformed values may slip through. Restrict log access for private repositories.
Step 6: Review third-party actions
For critical actions, consider forking into your organization or vendoring the code after review.
Verify
Search workflows for uses: lines with tags or branches instead of SHAs.
- tj-actions/changed-files Compromise (Mar 2025): A GitHub Action Leaks CI Secrets Incident Teardowns
- Detecting GitHub Actions Supply Chain Attack: Sentinel and GuardDuty Detections Detection & Response
- CIO Brief: Pipeline Supply-Chain Risk Explained CIO Briefings