Because GitHub Actions are fetched from Git, the advice was to pin to a full SHA instead of a tag. This is because tags are mutable and susceptible to supply-chain attacks where an attacker points a previously safe tag at malicious code.
For example, an old workflow looks like:
Here’s how I set up lockfiles.
Install the gh-actions-lock extension to the gh CLI :
The workflow now uses vX.Y.Z tags and looks like this:
And it generates a lockfile at .github/workflows/actions.lock :
Commit modified workflows and the new lockfile.
Renovate and Dependabot #
Good news, both already support lockfiles ! Your periodic updates will also update the lockfile. Remember to use cooldowns .
GitHub also recommends verifying lockfiles in CI to ensure it’s up-to-date and not corrupt.
They suggest copying this verify-lockfile.yml into your repo. I decided to put it into my existing lint workflow, but in its own job so it runs independently and in parallel:
Note I’m using the lightweight ubuntu-slim runner here. Also, it’s pinning to v0.4.1; we’ll have to update that at some point or figure out a way to automate it. That’s for another time.
Don’t forget that we just modified the actions in a workflow, so need to relock with gh actions-lock . Nothing actually changes if adding to lint.yml because it’s already locking actions/checkout . But if you created a new file like verify-lockfile.yml , you’ll need to relock for that. The CI will let you know.
zizmor is a security linter for GitHub Actions and strongly recommended . If you don’t use it, please do.
Versions before v1.32.0 tell you to hash-pin actions, and v1.32.0 is the first to support lockfiles.
I use zizmor in prek , so add/update zizmor in .pre-commit-config.yaml :
python-pillow/Pillow#10428
python/release-tools#477
python/miss-islington#758
python/cpython#161811
Header photo: Slaymaker Barry Co. Sprocket Locks in The Bearings (vol. XII no. 23, 2nd January 1896) in the Smithsonian Libraries and Archives , with no known copyright restrictions .
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
