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

URL: https://www.devopsness.com/blog/github-actions-workflow-lockfiles
Author: Kiril Urbonas
Published: 2026-10-26
Updated: 2026-10-26
Categories: DevOps
Tags: CI/CD, Security, GitHub Actions, Supply Chain, DevSecOps

Summary: 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.

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

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
# 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
# .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](/blog/oidc-federation-github-actions-aws).

## Where it still leaks

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

| Gap | Status in preview | What 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 actions | Blocking error until you pass `--migrate-local-actions` or `--ignore-local-actions` | Migrate, then relock |
| Container images (`container:`, `docker://`) | Not locked; images without `@sha256:` warn | Pin images by digest |
| Moving a floating ref back to an older commit | Not detected | Review lockfile diffs; prefer exact tags |
| GitHub Enterprise Server | Not supported | Keep 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](/blog/npm-supply-chain-ci-hardening).

## 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

- [GitHub Changelog: workflow lockfiles in public preview](https://github.blog/changelog/2026-10-14-github-actions-workflow-lockfiles-in-public-preview)
- [GitHub Docs: Workflow dependency lockfiles](https://docs.github.com/en/actions/concepts/security/workflow-dependency-lockfiles)
- [github/gh-actions-lock README](https://github.com/github/gh-actions-lock)

