Join our Newsletter — 33% off our NHI Course
Home› Guides› How to Pin GitHub Actions to Commit SHAs:…
Guide Software & AI Supply Chain

How to Pin GitHub Actions to Commit SHAs: Bulk Pinning, Updates and Policy

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 11 November 2026 13 min read
On this page

A workflow that references an action by tag or branch runs whatever code that tag points to on the day of the run, with the job's secrets and token in reach. This guide covers one task: moving every action reference in an organisation from mutable tags to full-length commit SHAs, keeping those pins current with Dependabot, and then turning on the policy that fails any unpinned workflow. It also covers workflow dependency lockfiles, which GitHub now describes as the stronger option where they are available. It is written for platform engineers and organisation owners who already run GitHub Actions. For the wider credential picture see the GitHub and GitHub Actions Security Guide; this page goes deeper on pinning alone.

This is an independent guide from NHI Mgmt Group, based on GitHub's public documentation as of November 2026. It is not sponsored or reviewed by GitHub. Product features change, so confirm settings against GitHub's current documentation.

Key takeaways

  • Pin to all 40 characters. GitHub's secure use reference recommends pinning to a full-length commit SHA because replacing the code behind it would need a SHA-1 collision for a valid Git object, while a tag "can be moved or deleted" by anyone who gains access to the action's repository.
  • Keep a version comment on the same line. Dependabot updates a reference of the form owner/action@<sha> # v4.2.1 together with its comment, so pins stay readable and current.
  • Turn on the pinning policy last. The checkbox "Require actions to be pinned to a full-length commit SHA" fails every workflow that uses an unpinned action, including GitHub-authored and your own organisation's actions, so pin first, then enforce.
  • Lockfiles go further than pins. Workflow dependency lockfiles (public preview, GitHub Enterprise Cloud) record transitive actions and the source repository's numeric identity; GitHub says SHA pinning in workflow files is no longer necessary for repositories that adopt one.
  • Pinning moves the review burden. Dependabot does not raise vulnerability alerts for actions pinned to SHAs, so your update pull requests and their review become the control.

When you need this

Pinning is the right task when any of these is true: workflows reference third-party actions by @v4, @main or similar; jobs that use those actions hold cloud credentials, publishing tokens or a writable GITHUB_TOKEN; or an audit has asked you to show that the code your pipelines run is fixed and reviewed. It sits beside two other controls. The allowed actions policy decides which actions may run; pinning decides which version runs; token scoping decides what that code can reach. See How to Restrict GITHUB_TOKEN Permissions in Workflows for the third.

Reference formWhat runsCan it change under you?Use it for
owner/action@mainLatest commit on the branchYes, on every pushNothing in production workflows
owner/action@v4Whatever the major tag points toYes, maintainers move it by designShort-lived experiments only
owner/[email protected]The commit the tag points toYes, if the tag is force-pushed, unless it belongs to an immutable releaseBetter, still trust-based
owner/action@<40-char SHA> # v4.2.1Exactly one commitNoThe default for all workflows
Lockfile entryThe locked commit, checked against the recorded owner and repository IDsNo, and transitive actions are coveredRepositories on Enterprise Cloud that can adopt the preview

Immutable releases help maintainers: GitHub's guidance for action authors notes that a tag tied to a GitHub release cannot later be moved, whereas plain major and minor tags are moved by force-push as new versions ship. As a consumer you cannot tell from a uses: line which kind of tag you have, which is why the SHA is the safer default.

Before you start

  • Access: write access to the repositories you will change, and organisation owner (or enterprise owner) rights to set the actions policy later.
  • Tooling: the GitHub CLI (gh) for resolving tags and, if you use lockfiles, the github/gh-actions-lock extension.
  • Inventory: a list of every uses: line in .github/workflows/ and in any action.yml or action.yaml file for composite actions you maintain. Code search for uses: scoped to your organisation and the path .github/workflows gives a first cut; a clone-and-grep across repositories gives a complete one.
  • Classification: mark each reference as GitHub-authored, your own organisation, Marketplace third party, local (./path), Docker image or reusable workflow. They are treated differently below.
  • Baseline: record the count of unpinned references per repository. It is your first metric and your proof of progress.

Step-by-step: bulk pinning

  1. Resolve each tag to a commit, from the action's own repository. GitHub warns that you should verify the SHA comes from the action's repository and not a fork. Resolve the tag you already use (for example v4.2.1, not v4) to the commit it points to with the GitHub CLI or git ls-remote against the canonical repository. For an annotated tag, git ls-remote prints two lines: the tag object's own hash and a second line ending in ^{}, which is the object the tag points to. Pin to the ^{} value, which is the commit, not the tag object hash.
  2. Prefer the exact patch version. If a workflow uses @v4, resolve the newest v4.x.y release the maintainers have published and pin to that, so the comment names a real release Dependabot can track. If the pinned commit has no associated tag, GitHub notes that Dependabot will update to the latest commit, which may differ from the latest release.
  3. Rewrite the reference with a comment. Use the form uses: owner/action@<full SHA> # v4.2.1 on one line. Keep the comment on the same line; Dependabot updates it along with the SHA.
  4. Do the same inside composite actions you own. A composite action's action.yml can call other actions. Pinning the outer action does not pin what it calls unless its own file is pinned. This is the gap lockfiles close for the actions you consume but do not own.
  5. Pin container images by digest. For docker:// steps and job or service container: images, reference the image by digest in the form image@sha256:<digest>, as Docker's own pull syntax allows, so the same image runs every time. GitHub notes that Dependabot does not support docker:// references for GitHub Actions, so track those through your container image update process.
  6. Leave local actions and decide on reusable workflows. Local ./path actions run from the same commit as the workflow and are not pinned. The pinning policy still allows reusable workflows to be referenced by tag. Our recommendation: pin the ones you call from other organisations to a SHA anyway, and govern your own through the allowed list.
  7. Ship in small pull requests. One pull request per repository, or per workflow for large monorepos, with the diff limited to uses: lines. CI on the pull request proves the pinned versions behave as the tags did.

Keep pins current with Dependabot

Add or extend .github/dependabot.yml with the github-actions ecosystem. GitHub's example uses package-ecosystem: "github-actions", directory: "/" and a weekly schedule.interval; the value / tells Dependabot to scan .github/workflows and the root action file. If you keep composite actions in other folders, use the directories key, which supports globbing (the singular directory key does not). Dependabot version updates then open pull requests that move both the SHA and its comment.

One trade-off matters. GitHub states that Dependabot only creates alerts for vulnerable actions that use semantic versioning and will not create alerts for actions pinned to SHA values. Once you pin, the weekly version update pull requests are how you pick up fixes, so they need an owner and a service level (our suggestion: review within five working days, sooner for security fixes announced by the action's maintainers).

Optional: adopt a workflow dependency lockfile

Where you run GitHub Enterprise Cloud and accept a public preview, GitHub's lockfile feature replaces per-line pinning. Install the extension with gh extension install github/gh-actions-lock, then run gh actions-lock from the repository root (or gh actions-lock .github/workflows/ci.yml to onboard one workflow). It writes .github/workflows/actions.lock, recording for each dependency the ref, the resolved commit, and the source repository's owner_id and repo_id. At run time GitHub uses those IDs to confirm the repository behind the name is still the one you locked, and transitive dependencies are covered.

  • Review the diff: the tool also rewrites uses: lines to the specific resolved version (for example @v3 to @v3.1.0).
  • Check your allowlist: with a lockfile, the allowed actions policy checks locked commit SHAs, so tag-specific allowlist entries such as actions/checkout@v6 no longer match; use actions/checkout@* or a full SHA.
  • Protect the file: add .github/workflows/actions.lock to CODEOWNERS with required code owner review, and run gh actions-lock --verify on pull requests as a required check.
  • Treat identity changes as incidents in waiting: GitHub says a changed owner_id or repo_id means the repository behind the name is not the one originally locked. Investigate before merging.
  • Relock deliberately: if the tool reports that a tag now points to a different commit, read the upstream history first, then use gh actions-lock --relock. Never hand-edit the lockfile.

Dependabot regenerates the matching lockfile entry when it bumps an action in an onboarded workflow, but it does not onboard new workflows.

Step-by-step: turn on the policy

  1. Pick the scope. The SHA pinning checkbox sits under each option of the allowed actions policy at enterprise, organisation and repository level (it is hidden where Actions is disabled). Start with one pilot organisation or repository.
  2. Set it. At repository level: Settings, Actions, General, Actions permissions, then tick "Require actions to be pinned to a full-length commit SHA" and Save. Organisation and enterprise settings carry the same option under their Actions policies.
  3. Tighten the allowed list at the same time. The option "Allow OWNER, and select non-OWNER, actions and reusable workflows" accepts patterns such as octocat/*, octokit/*, up to 1,000 entries. Since August 2025 an entry prefixed with ! blocks a specific action or version and is evaluated last, so *, !space-org/action@* allows everything except that action.
  4. Watch the first runs. Any workflow that still uses an unpinned action fails. A failure in the pilot is the test working; fix the reference rather than relaxing the policy.
  5. Widen in rings. Pilot, then teams with the fewest third-party actions, then everyone. For lockfiles, GitHub's "Require lockfile" policy has an Evaluate mode on GitHub Enterprise, with results under Policy insights, before you set it to Active.

Verify it worked

  • Search again: the inventory query from "Before you start" should return no uses: lines without a 40-character hexadecimal ref, apart from local actions and the reusable workflow exceptions you accepted.
  • Test the guard: in the pilot repository, open a branch that changes one reference back to a tag. The run should fail with a pinning error; delete the branch.
  • Check Dependabot: the repository's Dependabot page should list the github-actions ecosystem with a recent check, and the first update pull requests should change SHA and comment together.
  • Check the audit trail: changes to Actions policies at organisation and enterprise level appear in the audit log. See the GitHub Audit Log Detection Guide.

Rollback and common errors

SymptomLikely causeFix
Workflow fails after the policy is enabledAn unpinned reference remains, often in a composite action or a rarely run workflowPin it; if production is blocked, untick the checkbox for that scope as the rollback, fix, then re-enable
Reference cannot be resolvedThe tag object hash was copied instead of the commit, or the SHA came from a forkUse the ^{} line from git ls-remote against the canonical repository
Dependabot updates the SHA but not the commentThe comment is on a separate line or in a different formPut # vX.Y.Z on the same line as the reference
Dependabot moves to an untagged commitThe original pin had no associated tagRe-pin to a tagged release commit
Allowlist stops matching after lockfile adoptionTag-specific allowlist entriesUse owner/action@* or full SHAs in the allowlist
Lockfile verification fails on a pull requestA workflow changed without regenerating the lockfileRun gh actions-lock and commit the result

Rollback is a single setting: clearing the pinning checkbox (or setting the lockfile policy back to Evaluate) restores the previous behaviour immediately. The pinned references themselves need no rollback; they run the same code the tags pointed to when you pinned them.

Hardening afterwards

  • Review update pull requests as code changes: a changed SHA means different code will run with your secrets. Read the action's release notes and diff for actions that run in privileged jobs.
  • Scope what pinned code can reach: read-only token defaults and short-lived cloud credentials limit the damage if a pinned version is itself bad. See GitHub Actions OIDC Federation Hardening Guide.
  • Review before allowing: a Marketplace verified creator badge means GitHub has verified the publisher's identity, which GitHub's secure use reference calls a useful signal; it is not a review of every version, so review the action itself before allowing it.
  • Add the other CI/CD controls: see How to Find GitHub Workflows Exposed to pull_request_target Abuse and How to Audit CI/CD Secrets Scope.

Measure it

Our suggested metrics, reviewed monthly: unpinned third-party references per organisation (target zero); share of organisations with the pinning policy or lockfile policy active (target 100%); median age of open Dependabot github-actions pull requests (target under five working days); repositories with a github-actions Dependabot configuration (target 100% of those with workflows); and lockfile verification failures merged without regeneration (target zero).

Framework mapping

FrameworkReferenceHow pinning supports it
NIST SP 800-53 Rev 5SI-7 Software, Firmware, and Information Integrity; SR-4 Provenance; CM-2 Baseline ConfigurationFixes and records the exact third-party code a build runs
NIST CSF 2.0ID.AM-02; PR.PS-02Inventory of actions in use; maintained and updated by risk
MITRE ATT&CKT1195.001 Compromise Software Dependencies and Development ToolsReduces exposure to a modified dependency or development tool
OWASP CI/CD Top 10CICD-SEC-3 Dependency Chain AbuseSee the OWASP CI/CD Top 10 CICD-SEC-3 Dependency Chain Abuse Guide

Practitioner checklist

  • Inventory every uses: reference across workflows and composite actions, and record the unpinned count.
  • Resolve each tag to its commit in the action's own repository, never a fork.
  • Pin to the full 40-character SHA with a same-line # vX.Y.Z comment.
  • Pin container images by digest and track them outside Dependabot's github-actions updates.
  • Configure Dependabot for github-actions, using directories for composite actions in subfolders.
  • Assign an owner and review target for Dependabot action pull requests.
  • Enable "Require actions to be pinned to a full-length commit SHA" on a pilot, then widen in rings.
  • Where eligible, pilot workflow dependency lockfiles with CODEOWNERS and gh actions-lock --verify as a required check.

Standards and references

Related NHI Mgmt Group resources: GitHub and GitHub Actions Security Guide · How to Restrict GITHUB_TOKEN Permissions in Workflows · GitHub Organisation Security Checklist · CI/CD Pipeline Identity Security Guide

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 11 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org