GitHub Actions
Pin GitHub Actions to SHAs: Secure CI/CD Pipelines
Pinning an action by tag is easy to read. Pinning it by full commit SHA is easier to trust. The review goal is simple: a workflow should show exactly which third-party code can run inside CI.
Key takeaways for GitHub Actions SHA pinning
- GitHub's secure-use reference says pinning an action to a full-length commit SHA is currently the only way to use an action as an immutable release. [1]
- GitHub's workflow syntax reference says a step's `uses` reference can select a SHA, release tag, or branch name. [2]
- GitHub documents repository-level settings that can require actions and reusable workflows to be pinned to a full-length commit SHA. [3]
- OpenSSF Scorecard includes a Pinned-Dependencies check for GitHub Actions workflows and Dockerfiles. [4]
- SHA pinning reduces one dependency-integrity risk, but it should sit beside token limits, trusted triggers, and workflow review. Token scope and pull-request trigger choices still matter.
Pin third-party actions where CI trust matters
GitHub's secure-use reference is direct: a full-length commit SHA is the current way to use an action as an immutable release. [1] For CI/CD, that matters because a workflow step can run third-party code before the rest of the job touches build artifacts, repository tokens, cloud credentials, or release permissions.
This is not an argument for freezing dependencies forever. It is an argument for moving action upgrades into reviewable pull requests instead of letting a mutable tag or branch decide what runs during the next pipeline execution.
Tags and branches are readable, but SHAs are reviewable
GitHub's workflow syntax reference describes the `jobs.<job_id>.steps[*].uses` field as the way to select an action, and it documents three common references: a SHA, a release tag, or a branch name. [2] The same reference says using the commit SHA of a released action version is the safest choice for stability and security. [2]
A tag may be the right communication label for humans, but the SHA is the dependency lock. A practical pattern is to pin the `uses` value to a full SHA and add a short comment with the intended upstream version, such as `# v4.2.0`, so update tools and reviewers have context.
Start with workflows that have real authority
Not every workflow has the same blast radius. The first pinning pass should cover jobs that publish packages, deploy to cloud accounts, upload release artifacts, run security tools with elevated permissions, or write back to the repository.
- Release jobs: pin actions that build, sign, upload, or publish artifacts.
- Deployment jobs: pin actions that receive cloud credentials, OIDC trust, SSH keys, or environment approvals.
- Security jobs: pin third-party scanners before they receive repository content, SARIF upload permissions, or secrets.
- Pull-request automation: pin actions that label, comment, request reviews, or run around untrusted pull-request input.
That priority order matches the broader CI Tripwire posture: make the risky workflow decisions visible first, then clean up lower-privilege convenience workflows.
Repository policy can enforce full-SHA pins
GitHub documents repository settings that can limit which actions and reusable workflows are allowed. In that settings flow, GitHub says the "Require actions to be pinned to a full-length commit SHA" option requires actions to use a full-length commit SHA. [3]
That policy is useful after a repository has a clean baseline. Turning it on before the workflows are updated can break CI, but leaving it off forever means every future workflow change relies only on code review discipline.
SHA pinning needs an update loop, not a freeze
OpenSSF Scorecard's Pinned-Dependencies check includes GitHub Actions workflows in its dependency-pinning review. [4] That makes pinning visible as an ongoing repository-health signal rather than a one-time hardening chore.
The maintenance loop should be boring: track upstream versions, open reviewable update pull requests, read release notes for behavior changes, and keep the pinned SHA plus version comment together. If an action is no longer maintained or cannot be reviewed, replacing it may be cleaner than repeatedly updating it.
A first audit can start with every `uses:` line
Search workflow YAML for `uses:` and separate local actions, first-party actions, third-party actions, reusable workflows, Docker actions, and branch or tag references. For each third-party reference, decide whether the workflow should use a full-length SHA, an allowlist, or a repository policy. [2] [3]
For a local review queue, run gha-guard against the repository and inspect unpinned-action findings beside token-permission, trigger, timeout, and shell-context findings.
This article is informational and is not a substitute for a security review of your own workflows, repositories, or cloud accounts.
CI Tripwire has not commissioned independent expert review of this article. Read more about the organization byline at contributors and the source posture at sourcing.
Corrections can be routed through the corrections note. Sources: 4 entries, primary platform and project documentation, last reviewed 2026-06-07.
Sources
- GitHub Docs, Secure use reference.
- GitHub Docs, Workflow syntax for GitHub Actions.
- GitHub Docs, Managing GitHub Actions settings for a repository.
- OpenSSF Scorecard, checks documentation: Pinned-Dependencies.