GitHub Actions Pinning Policy
Every uses: entry in every GitHub Actions workflow across the publicala organization must be pinned to a specific version. This policy defines how to pin, what to pin to, and how to handle future deprecations without accumulating backlogs.
The Rule​
Every uses: line must be pinned. Floating references (@main, @master, or a branch name) are not allowed. Drive-by commits to the action's default branch would silently change CI behavior across the org.
How to Pin​
Pinning depth depends on who owns the action.
First-party actions (owned by GitHub, actions/*)​
Pin to the major version tag.
- uses: actions/checkout@v6
- uses: actions/cache@v5
- uses: actions/setup-node@v6
The major tag is mutable in principle, but GitHub controls the actions org. A tag-rewrite attack there requires GitHub itself to be compromised, which is outside the threat model for most workloads. Major tags automatically receive patch and minor updates, which keeps workflows current on security fixes without manual intervention.
Third-party actions (everyone else)​
Pin to a full commit SHA, with a trailing comment recording the human-readable version.
- uses: softprops/action-gh-release@c062e08bd532815e2082a85e87e3ef29c3e6d191 # v2.0.8
Tag-rewrite attacks on third-party repositories are a real risk. In March 2025, the tj-actions/changed-files action was compromised and its @v35 tag was rewritten to exfiltrate CI secrets from an estimated 23,000 repositories that pinned to the major tag. SHA pinning is immune because a SHA identifies an immutable Git object.
The trailing # vX.Y.Z comment keeps the pin human-readable when reviewing diffs and auditing workflows.
Current Minimum Versions​
As of 2026-04-16, the following majors are the lowest acceptable pins for actions/* actions (each of these declares using: node24 in its action.yml):
| Action | Minimum major |
|---|---|
actions/checkout | @v6 |
actions/cache | @v5 |
actions/cache/restore | @v5 |
actions/cache/save | @v5 |
actions/setup-node | @v6 |
actions/upload-artifact | @v7 |
actions/download-artifact | @v8 |
Earlier majors of these actions run on Node.js 20, which GitHub is sunsetting (forced Node 24 on runners from 2026-06-02; Node 20 removed from runners on 2026-09-16).
Handling Future Deprecations​
GitHub posts deprecation notices in workflow annotations several months before enforcement. When a new deprecation warning appears:
- Identify the next major version of the action that runs on the new Node runtime. Read
action.ymlat each candidate tag and check theusing:field, or consult the action's release notes. - Skim the changelog between the pinned major and the target major for behavioral breaking changes.
actions/upload-artifactandactions/download-artifactin particular have shipped behavioral breaking changes (unique artifact naming, implicit merge removal) alongside runtime bumps. - Bump one repository first and confirm CI stays green.
- Roll the same bump across the rest of the organization, one PR per repository.
- Update the minimum-version table in this document.
Drift Detection​
This policy does not yet mandate a specific tool for automated pin-drift detection. Two options are under evaluation:
- Dependabot: configured via
.github/dependabot.ymlin each repository. GitHub-native, no org-level shared configuration. - Renovate: installed as a GitHub App at the organization level, with a shared preset hosted in a central repository. One source of truth for the whole org.
The evaluation and rollout of one of these tools is tracked separately from this policy.
Related References​
- CI/CD Translation Reference for the GitLab-to-GitHub workflow mapping.
- Deploy Approval Pattern for environment protection rules.
- GitHub's official security hardening guide for Actions.