DevOps

How to Use GitHub Actions Workflow Lockfiles to Pin Every Dependency

GitHub's new actions.lock file records the exact commit behind each action. Here is how to create it, keep it current and avoid the allowlist trap.

Marcus Oyelaran

Security & DevOps Specialist

Published 7 min read
A programmer coding on a laptop and monitor in a stylish office setup.
On this page 9 sections

GitHub Actions workflow lockfiles record the exact commit behind every action your workflows use. You create .github/workflows/actions.lock with the gh actions-lock extension, commit it, and runs then use the recorded commits even if a tag moves. The feature entered public preview on October 14, 2026.

Tags move. That simple fact is the weak point of most CI pipelines, because a line like uses: some/action@v3 runs whatever code the tag points to today. GitHub Actions workflow lockfiles close that gap by recording the exact commit your workflow ran when you reviewed it.

This guide is for engineers who own CI pipelines and want a practical path to adopt the feature. It covers what the lockfile contains, the exact commands, the review step that matters most, and the limits GitHub itself documents. Recent supply chain incidents, such as the npm SlugFest attack, show why pinning matters. Backtrace covers CI and security changes by testing them against real pipelines.

What is a GitHub Actions workflow lockfile?

Hand holding a brass padlock, symbolizing security and protection

A workflow lockfile is a file that records the exact commit each action in your workflows resolves to. Your workflow files still reference actions by tag or branch. GitHub Actions then runs the commit in the lockfile, not whatever the tag points to at that moment.

According to GitHub's documentation on workflow dependency lockfiles, the file has a workflows section and a dependencies section. Each dependency entry records the ref, the exact commit, and the numeric owner and repository IDs of the source repository. Those IDs let GitHub confirm at run time that the repository behind the name is still the one you locked.

The lockfile also covers transitive dependencies, which are the actions your actions call. It does not extend to reusable workflow calls from other repositories. A reusable workflow is covered by the lockfile in the repository where it is defined.

Before this feature, teams pinned actions by hand to full commit SHAs. That worked, but the files became unreadable and updates were tedious. The lockfile keeps the workflow readable and moves the pinning into a reviewable file.

Why do moving tags put your pipeline at risk?

From below of long thin blue cables connected to row of small white connectors on system block in data center

A moving tag puts your pipeline at risk because the code behind it can change without any change in your repository. If an attacker takes over an action's repository, or a maintainer force-pushes a tag, your next run executes new code. Your workflow file shows no diff.

That is the pattern behind many supply chain attacks. We have covered it in the LiteLLM compromise, where trusted code changed under users' feet. CI runners are an especially rich target, because they often hold deploy keys and cloud credentials.

At Backtrace, we treat any unpinned third-party action as a standing risk in the pipeline. The risk is low on any given day and high on the one day it matters. A lockfile turns a silent change into a visible diff, which is the core of the benefit.

How do you create actions.lock step by step?

A classic MS-DOS terminal screen displayed on a laptop keyboard with vivid illumination.

Creating the lockfile takes a few commands. GitHub's how-to guide for locking workflow dependencies lists the steps. Follow them in this order.

  1. Check that every uses reference points to a supported, current version.
  2. Enable Dependabot for GitHub Actions before you create the lockfile.
  3. Install the extension from the repository root.
  4. Run the tool to scan every workflow.
  5. Review the full diff, then commit.

The commands look like this.

text
gh extension install github/gh-actions-lock
gh actions-lock
git diff
git add .github/ .
git commit -m "Lock workflow action dependencies"

To onboard a single workflow first, pass its path, for example gh actions-lock .github/workflows/ci.yml. That is the safer route for a large repository. Start with one low-risk workflow, confirm it runs, then expand.

One snag to know about: local path actions resolve from the repository root, not from the workflow file's directory. If a workflow is skipped because of a uses: ./… path, fix the path and run the tool again.

What does the lockfile change in your workflow files?

The extension does more than write the lockfile. It also edits your workflow files and action.yml files, and the diff is where you should spend your review time.

The changes fall into two groups. References become more specific, so @v3 may become @v3.1.0, though the commit stays the same. In-repository references are rewritten from ./… to a form that resolves to the running commit and needs no lockfile entry.

Read every line of that diff. A lockfile you did not review is just another file you trust blindly. GitHub says it plainly: locking does not determine whether a dependency is safe, so review dependencies before locking them.

That means the lockfile freezes what you approved, including a bad dependency. Audit first, lock second. If an action is abandoned or unfamiliar, replace it before you pin it.

How do you keep the lockfile current?

Software developer analyzing code on a tablet in a modern office workspace.

Keeping the lockfile current takes two habits. Rerun the tool when you add or change a workflow dependency, and let Dependabot handle version bumps. For onboarded workflows, Dependabot regenerates the matching lockfile entry in the same pull request, per GitHub's changelog announcement.

Moved branches and partial tags need special care. A reference like main or v3 is not re-resolved on a normal run. If you confirm the move was legitimate, relock on purpose.

text
gh actions-lock --relock

If the locked commit became unreachable, for example after a force-push upstream, you must accept the new commit explicitly.

text
gh actions-lock --relock --accept-moved

Treat those flags as a deliberate decision, not a way to clear an error. A moved commit is exactly the event the lockfile exists to catch. Check the upstream repository before you accept it.

Do not edit the lockfile by hand. If it looks wrong, fix the workflow files and regenerate it.

How should you review a lockfile change in a pull request?

Review a lockfile change like any dependency bump. The diff shows what will run, so read it with the same care you give application code.

Two fields deserve a close look. A changed commit value is the new code your workflows will run. A changed owner_id or repo_id is rare and may mean the repository behind the name is no longer the one you locked. Investigate that before merging.

The table below is a quick triage guide.

How should you review a lockfile change in a pull request?
Diff changeWhat it meansAction
New commit, same repo IDNormal version bumpRead the upstream release notes
Changed owner or repo IDThe name may point to a different repositoryStop and investigate
Commit changed with no workflow changeSomeone relockedAsk why, check for a moved tag
Hand-edited entryUnsupported changeRegenerate the file

Add a reviewer rule if your team can. A second pair of eyes on actions.lock changes catches the risky ones.

What is the allowlist trap after onboarding?

A worn 'STOP' sign placed on a cracked concrete pavement next to a yellow curb.

The allowlist trap is a quiet failure that appears after you commit the lockfile. If your organization allows actions by tag, such as actions/checkout@v6, those entries can stop matching once the extension makes references more specific.

GitHub's guide warns about this directly. Check your allowlist before you commit. Use a wildcard or the full commit SHA instead of a tag-pinned entry.

The symptom is a workflow that fails to start right after a clean-looking pull request. Teams lose an afternoon to it because nothing in the code changed. Look at the allowlist first.

A short pre-merge checklist avoids this.

  1. List every allowlist entry that uses a tag.
  2. Update each one to a wildcard or a full SHA.
  3. Merge the allowlist change before the lockfile.
  4. Run one onboarded workflow end to end.

That order means a failure points at one change, not two.

Can you enforce workflow lockfiles across an organization?

Yes. GitHub offers a Require lockfile policy, also in public preview. Enterprise, organization and repository administrators can require workflows to use lockfiles at their level.

Roll it out in stages. Start by onboarding your most sensitive repositories, the ones that deploy to production or hold cloud credentials. Then widen the policy as teams learn the workflow. The same staged approach worked in our GitLab critical patch guide, where the riskiest instances went first.

The changelog lists availability on GitHub Enterprise Cloud, Enterprise Cloud with data residency, Team and Free plans. Check your own plan and the current documentation before you plan a rollout, because public preview features can change.

Remember what a lockfile does not do. Dependabot only reports that onboarding is required when it bumps a dependency in a workflow with no lockfile entry. It does not onboard workflows for you, so you still need a person to run the first pass.

Adopt workflow lockfiles one workflow at a time

GitHub Actions workflow lockfiles give you what hand-written SHA pinning never did: a readable workflow and a reviewable record of what actually runs. The steps are short. Install the extension, run the tool, review the diff, fix your allowlist, and commit.

Start with one production workflow this week. Turn on Dependabot for Actions first, then onboard, then add the Require lockfile policy once the team is comfortable. Backtrace will keep testing the feature as it moves out of public preview.

What is the GitHub Actions workflow lockfile?
It is a file at .github/workflows/actions.lock that records the exact commit each action in your workflows resolves to. GitHub Actions then runs the recorded commit even if a tag or branch moves. You create and update it with the gh actions-lock extension for the GitHub CLI.
Does a workflow lockfile make my actions safe?
No. GitHub states that locking does not determine whether a dependency itself is safe. It freezes what you approved, so a bad dependency stays bad. Review each action before you lock it, and read the diff whenever a commit changes in a pull request.
How do I update actions.lock when a tag moves?
Normal runs do not re-resolve moved branches or partial tags such as v3. After you confirm the move was legitimate, run gh actions-lock --relock. If the locked commit is unreachable, you must add --accept-moved. Never edit the lockfile by hand.
Does Dependabot update the lockfile for me?
For onboarded workflows, yes. Dependabot regenerates the matching lockfile entry in the same pull request as a version bump, with no extra configuration. It does not onboard workflows, though, so you must run the first lockfile creation yourself using the gh actions-lock extension.

Written by

Marcus Oyelaran

Security & DevOps Specialist

11+ years experience

Marcus Oyelaran spent eleven years moving between platform and security teams, including four years as a security engineer embedded inside a DevOps org at a healthcare SaaS company handling PHI at scale. He's run more incident postmortems than he can count, and most of what he writes for Backtrace comes directly out of those postmortems: the secret that leaked through a build log, the IAM policy that was too permissive by one wildcard, the deploy that skipped a gate because someone was in a hurry. He holds an OSCP and spends an unreasonable amount of time arguing about supply chain security on internal Slack channels.

Credentials

  • OSCP (Offensive Security Certified Professional)
  • 11 years in DevOps and security engineering
  • Former security engineer, healthcare SaaS platform (HIPAA-regulated infrastructure)