The issue opens pre-filled with this page title and URL.
You probably use GitHub actions such as actions/checkout@v4 in your
workflows. That @v4 looks harmless, yet it is a security hole that has
already enabled real attacks. This guide explains why, and how to protect
yourself.
What you will learn
Understand the danger of moving tags (@v4, @main, @latest)
Recognise a tag-moving attack, the tj-actions/changed-files way
Pin an action to its commit SHA, with a version comment
Find the SHA of an action through the API, the CLI or the GitHub interface
Automate the conversion and the updates with pin-github-action and Dependabot
Check how well pinning covers a whole repository
What is wrong with @v4?
The @v4 suffix seen everywhere in workflows names a Git tag. Behind that
harmless habit hides a moving reference, a structural weakness this section
takes apart, first through an image, then in technical terms.
In technical terms
A Git tag such as @v4 is simply a label stuck on a commit. The problem?
That label moves: anyone with access to the repository can shift it to
another commit.
This is not science fiction. In March 2025, the popular action
tj-actions/changed-files was compromised in exactly this way.
On day 1 the @v4 tag points to commit abc123, legitimate and validated; on day 30 the tag is moved to commit xyz789, malicious; on day 31 your workflow using action@v4 runs xyz789 and has its secrets stolen, GITHUB_TOKEN included.tag moved!Day 1tag @v4Commit abc123legitimate code, tested, validatedDay 30tag @v4Commit xyz789malicious code, steals your secretsDay 31: your workflowuses: action@v4 → xyz789Secrets stolen!GITHUB_TOKEN, etc.
Day 1: you use action/example@v4, which points at commit abc123,
legitimate code, tested and reviewed.
Day 30: an attacker compromises the maintainer's account (phishing, weak
password, stolen token, and so on).
The attacker moves the tag: @v4 now points at a new commit xyz789
holding malicious code.
Day 31: your workflow runs. It fetches @v4, and runs the malicious
code without you noticing anything.
Result: your secrets (GITHUB_TOKEN, API keys, credentials) are
exfiltrated to the attacker.
The fix: pin to a SHA
Instead of trusting a moving label, use the cryptographic fingerprint (the
SHA) of the commit. It is like handing over the exact fingerprint of the code
you want to run.
# ❌ Dangerous: a mutable tag, it can change at any moment
Why the # v4.2.2 comment? It records which version that SHA corresponds
to. It is purely informative, for you and for Dependabot, but the SHA is what
carries the security.
How do you find the SHA of an action?
You now know why to use a SHA. How do you find it? Several methods exist, from
the simplest to the most automated.
Method 1: through the GitHub API (fast)
The most direct request queries the GitHub REST API: it returns the
commit SHA behind any tag, with nothing to install.
Terminal window
# Get the SHA of tag v4.2.2 of the checkout action
If you prefer a graphical interface, app.stepsecurity.io
offers a simple path:
Paste your workflow YAML into the interface
The tool converts every tag into a SHA automatically
Copy the secured result
Replace your workflow file
Bonus: StepSecurity also reviews other security aspects of your workflows
(permissions, exposed secrets, and so on).
Keeping the SHAs current (without effort)
A pinned SHA is good. But actions receive security fixes and new features. How
do you stay current without going back to mutable tags?
Solution 1: Dependabot (recommended)
Dependabot watches your dependencies and opens pull requests automatically
when new versions land:
.github/dependabot.yml
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
cooldown:
default-days: 7# Quarantine: never a release published the same day # Checks every week
commit-message:
prefix: "ci"# Commit prefix: "ci: ..."
How it works: Dependabot reads the # v4.2.2 comment in your workflows.
When v4.2.3 ships, it opens a pull request updating both the SHA and the
comment. All you have to do is review and merge.
Solution 2: Renovate (an alternative)
Renovate is an alternative to Dependabot with more configuration options:
permissions: {} at the workflow level, contents: read granted only to the job that needs it
Every action pinned by SHA, with a version comment
persist-credentials: false on actions/checkout, so the GITHUB_TOKEN does not stay in the git configuration
Version comments that Dependabot can act on
No dubious third-party action
Recap: three steps to secure your workflows
Three concrete actions are enough to move from a vulnerable repository to
pinned and maintained workflows.
Convert every workflow with pin-github-action or StepSecurity
Configure Dependabot to keep the SHAs current automatically
Check regularly with Scorecard that nothing was forgotten
Key points
A Git tag (@v4, @main, @latest) is a moving reference: the maintainer, or an attacker, can shift it to any code.
The tj-actions/changed-files attack of March 2025 exploited exactly that mechanism to exfiltrate the secrets of thousands of pipelines.
Pinning an action to its commit SHA (40 characters) guarantees the pipeline always runs the same verified code.
The # v4.2.2 comment after the SHA is informative: it lets Dependabot offer version updates.
You do not pin by hand: pin-github-action or StepSecurity convert the workflows, Dependabot or Renovate keep the SHAs current.
The official actions/* actions get pinned too; any code running in CI deserves to be frozen.
Check your understanding
Make sure the essentials of this guide are yours. The questions only
cover what was explained here.
Knowledge check
Check what you have learned with this interactive quiz
6 questions
6 min
70% to pass
How it works
The timer starts when you click Start
Multiple choice, true/false and short answer questions
You can move between questions
Detailed results are shown at the end
Starts the quiz and the timer
⏱️--:--
0 / 6
Review
(0/0)
--:--
0%
0Correct
0To review
0:00Time
-Level
Score by domain
A domain groups several guides and gets several questions, so its score is more reliable than a per-topic score, which often rests on a single question.
Summary
Strengths
No topic passed at 80% on at least two questions yet.