GitHub Actions offer a powerful and flexible infrastructure for CI/CD, deployments and monitoring. But every external dependency we include opens a potential door for supply-chain attacks. One simple, effective, and low-cost way to seal that door is pinning your Actions to specific commit SHAs. In this article, we’ll explore the risks, walk through how to implement SHA pinning smoothly, and show you how to automate the process so you can keep everything under control without getting a headache.
Why SHA Pinning Is More Than a Minor Detail
Imagine this workflow step:
- uses: actions/checkout@v3
Today, that tag points to a secure commit, but tomorrow, someone could redefine it.
In an actual March 2025 attack, tj-actions/changed-files@v1 was hijacked to leak CI secrets and credentials into logs across 200+ repositories in minutes.
The lesson? Tags are mutable, and mutable means vulnerable. GitHub itself recommends always using a full-length commit SHA, which is immutable and can’t be changed retroactively.
How to Pin Actions to SHAs (and Keep Them Updated)
Replace Tags with SHAs Replace any tag label reference with the corresponding SHA:
This action first enforces SHA pinning and fails the pipeline if any mutable ref is found, and then runs only after pinning is verified, ensuring a known good base.
In Conclusion
Pinning GitHub Actions to commit SHAs is a small change that yields enormous security benefits. It guarantees that only the code you’ve approved ever runs in your CI, closing the door on tag-tampering attacks. When combined with enforcement, least-privilege tokens, and strict allow-lists, you create a CI pipeline that’s both powerful and safe.
These Solutions are Engineered by Humans
Did you find this article interesting? Are you an “under the hood” kind of person? We’re really big on automation and we’re always looking for people in a similar vein to fill roles like this one as well as other roles here at Würth Phoenix.
Gabriele Bocchi
Software Engineer - IT System & Service Management Solutions at Würth IT Italy
Author
Gabriele Bocchi
Software Engineer - IT System & Service Management Solutions at Würth IT Italy
In my previous posts of this series, we explored how to handle, filter, route, and enrich alerts generated by NetEye and forwarded to Jira Operations: https://www.neteye-blog.com/blog/2026/03/25/jira-operations-tips-tricks-for-neteye-users-part-1/ https://www.neteye-blog.com/blog/2026/06/15/jira-operations-tips-tricks-for-neteye-users-part-2/ In this article, I'll show you how we automated the creation of customer Read More
If you spend enough time working on Linux, your home directory slowly becomes a reflection of how you like to work. A few aliases are added to your shell. Git gets its own configuration. Your editor starts accumulating plugins and Read More
How Terraform has turned our NetEye Cloud Elastic configuration management into a declarative, verifiable, and repeatable process that improves governance, security, and operational speed. From Manual Configuration to a Declarative Platform The configuration of an observability and security platform quickly Read More
TL;DR Results: GitHub Actions run 32970330873 at commit 1846eb4a863015cbc0a3c75431b42d138b8706c3 This experiment measures two different workloads in Go 1.27 and .NET 10/.NET 11(preview): Raw crypto: one ML-KEM-768 encapsulation/decapsulation round trip versus one P-256 ECDH shared-secret round trip. TLS: a fresh authenticated TLS 1.3 Read More
In a previous post, I wrote about the challenges of building a public GitHub organization correctly: The need for structure, consistency, and enforcement rather than relying on memory. What I didn't cover was how we actually solved it. The short Read More