Skip to main content
GitHub Actions Workflow Lockfiles: Pin Every Action, Including the Ones You Can't See

GitHub Actions Workflow Lockfiles: Pin Every Action, Including the Ones You Can't See

KU
• 6 min read•1 view

GitHub now records the exact commit of every direct and transitive action in .github/workflows/actions.lock. Here is how to adopt it, what it fixes that SHA pinning never did, and where it still leaks.

Key takeaways

  • GitHub Actions workflow lockfiles, in public preview since October 14, 2026, record the exact commit and source repository of every direct and transitive action in .github/workflows/actions.lock.
  • Generate one with the gh actions-lock extension, verify it in CI, and let Dependabot update it.
  • It replaces SHA pinning but does not yet lock container images or cross-repo reusable workflows.

Workflow lockfiles stop actions from changing underneath you. gh actions-lock writes .github/workflows/actions.lock, recording the commit and source repository of every action you use, including transitive ones. GitHub Actions then runs the locked commits even if a tag moves. It entered public preview on October 14, 2026; adopt it now on your highest-risk repos.

The problem SHA pinning never solved

uses: actions/setup-node@v4 is a pointer, not a version. Tags and branches can move after you reviewed a workflow, so tomorrow's run can execute different code. That's how the March 2025 tj-actions/changed-files compromise worked: the attacker repointed existing version tags to a malicious commit, and every workflow referencing those tags ran it on the next push.

The standard advice was to pin full commit SHAs. That helps, with three gaps:

  • Transitive actions. Your pinned composite action can itself call some-org/helper@v2. You pinned the outer layer; the inner one still floats.
  • Repository identity. A SHA says which commit, not which repository. If an action's owner is renamed or deleted and the name is re-registered, the reference can resolve somewhere you never reviewed.
  • Readability. Forty-character SHAs with a # v4.2.1 comment are hard to review and easy to let rot, so most teams quietly stop updating them.

The lockfile addresses all three. Each entry records the ref your workflow asked for, the commit it resolved to, and the numeric owner_id and repo_id of the source repository, so the runner can confirm the repository is still the one you locked. Per GitHub's docs, SHA pinning in workflow files becomes unnecessary once a repository uses a lockfile.

Adopt it in one repository

The tool is a GitHub CLI extension. It's pre-1.0, so the format and flags may change.

bash.bash
# Install the extension (requires an authenticated gh)
$ gh extension install github/gh-actions-lock

# From the repo root: pin every resolvable action and write actions.lock
$ gh actions-lock
$ git diff .github/workflows/        # review what got pinned
$ git add .github/workflows/ && git commit -m "ci: add workflow lockfile"

# After changing any uses: line, rerun to update the lock
$ gh actions-lock

# Advance moved refs (like v4 or main) to their current upstream commit, deliberately
$ gh actions-lock --relock

Review the generated diff like any dependency bump. Locking proves you'll run the same code every time; it doesn't prove that code is safe.

Then stop a stale or tampered lockfile from merging. The extension ships a verification workflow; a trimmed version:

yaml.yaml
# .github/workflows/verify-lockfile.yml
name: verify-lockfile
on:
  pull_request:
  push:
    branches: [main]
permissions:
  contents: read
jobs:
  verify:
    runs-on: ubuntu-latest
    env:
      GH_TOKEN: ${{ github.token }}
    steps:
      - uses: actions/checkout@v7.0.1
        with:
          persist-credentials: false
      - run: gh extension install github/gh-actions-lock --pin v0.2.0
      - run: gh actions-lock --verify

Run gh actions-lock once more after adding this file so the verifier is itself locked. For a fast pre-commit hook, gh actions-lock --verify-local checks offline that every uses: has an entry. It checks coverage only, not provenance, so keep --verify in CI.

Roll it out across an org

Adoption is per workflow: once a workflow is onboarded, every dependency it uses must have a lockfile entry, and GitHub Actions runs the recorded commit. Admins at the enterprise, organization, or repository level can turn on the Require lockfile policy, also in public preview, to make lockfiles mandatory across their scope.

A sane order:

  1. Start with workflows that hold secrets or deploy. Release, publish, and deploy workflows are where a hijacked action does the most damage.
  2. Turn on Dependabot version updates for Actions. For onboarded workflows, Dependabot regenerates the matching lockfile entry in the same PR, so updates stay reviewable instead of manual.
  3. Enable Require lockfile per repository, then per org, once the verify job is green everywhere.

This pairs well with short-lived cloud credentials, so even a compromised step can't walk away with long-lived keys; see OIDC federation from GitHub Actions to AWS.

Where it still leaks

The extension's README is candid about current limits, and they matter for a threat model:

GapStatus in previewWhat to do meanwhile
Cross-repo reusable workflows (jobs.<id>.uses)Not locked (issue #179)Pin those calls to a full SHA
Local ./ actions that call remote actionsBlocking error until you pass --migrate-local-actions or --ignore-local-actionsMigrate, then relock
Container images (container:, docker://)Not locked; images without @sha256: warnPin images by digest
Moving a floating ref back to an older commitNot detectedReview lockfile diffs; prefer exact tags
GitHub Enterprise ServerNot supportedKeep SHA pinning

The reusable workflow gap is the one to watch. GitHub's changelog says lockfiles cover "reusable workflow dependencies," but the extension's own README says cross-repository reusable workflows called at the job level aren't locked yet. Until that issue closes, assume they float. We covered the wider set of CI hardening controls after the npm worms in hardening CI against supply chain attacks.

Questions people ask

What is a GitHub Actions workflow lockfile?

It's a machine-generated file at .github/workflows/actions.lock that records, for every action a workflow uses, the requested ref, the exact commit it resolved to, and the source repository's numeric IDs. GitHub Actions runs the locked commit even if the tag or branch later moves. It's generated by the gh actions-lock CLI extension and is in public preview.

Do I still need to pin GitHub Actions to commit SHAs?

Not for workflows covered by a lockfile, according to GitHub's docs, because the lockfile pins direct and transitive actions and records repository identity. Keep SHA pinning where the lockfile doesn't reach yet: cross-repo reusable workflows, GitHub Enterprise Server, and container images, which you should pin by @sha256: digest.

Does Dependabot update the actions.lock file?

Yes. For workflows that are onboarded to a lockfile, Dependabot version updates regenerate the matching lockfile entry in the same pull request. You review one PR that changes both the uses: reference and its locked commit, with no extra Dependabot configuration needed.

The decision, concretely

  • Repo with deploy or publish workflows? Adopt the lockfile this week and add gh actions-lock --verify to CI.
  • Already SHA-pinned everything? Adopt anyway; you gain transitive coverage and repo identity checks.
  • Heavy use of cross-repo reusable workflows? Lock the rest, and keep SHA pins on those calls until issue #179 lands.
  • On GitHub Enterprise Server? Not supported yet; stay on SHA pinning.

The call we'd make

Adopt lockfiles now on every repository that deploys or handles secrets, even in preview. The tool is pre-1.0, but the failure mode it fixes, a moved tag running unreviewed code with your credentials, has already happened at scale. Lock, verify in CI, let Dependabot drive updates, and pin the gaps by hand until GitHub closes them.

Sources

Explore topics:CI/CDDevOps
React
Share this post
KU

Kiril Urbonas

AI Engineer

560 articles
View all articles by Kiril Urbonas

You might have missed

Evergreen posts worth revisiting.