Summary
Pin all GitHub Actions references in workflow files to full commit SHAs instead of mutable version tags to prevent supply-chain attacks.
Motivation
Git tags are mutable — anyone with write access to an action's repo can rewrite a tag to point to a malicious commit. This was exploited in the tj-actions/changed-files incident (March 2025), where attackers rewrote all version tags on an action used by ~23,000 repos, exfiltrating CI secrets from every workflow that ran during the compromised window. Workflows pinned to SHAs were completely unaffected.
GitHub's own security hardening guide recommends SHA pinning as "the only way to use an action as an immutable release."
Actions to pin
In release.yml:
| Action |
Current |
Priority |
azure/login@v2 |
tag |
High (3rd-party, handles signing credentials) |
azure/artifact-signing-action@v1 |
tag |
High (3rd-party, handles signing credentials) |
actions/checkout@v4 |
tag |
Medium (1st-party) |
actions/upload-artifact@v4 |
tag |
Medium (1st-party) |
actions/download-artifact@v4 |
tag |
Medium (1st-party) |
Other workflow files (e.g., ci.yml) should also be updated for consistency.
Implementation
- Look up the current commit SHA for each action's version tag
- Replace each
uses: line with uses: owner/action@<full-sha> # <version-tag>
- Add
.github/dependabot.yml to automatically update pinned SHAs:
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
References
Summary
Pin all GitHub Actions references in workflow files to full commit SHAs instead of mutable version tags to prevent supply-chain attacks.
Motivation
Git tags are mutable — anyone with write access to an action's repo can rewrite a tag to point to a malicious commit. This was exploited in the tj-actions/changed-files incident (March 2025), where attackers rewrote all version tags on an action used by ~23,000 repos, exfiltrating CI secrets from every workflow that ran during the compromised window. Workflows pinned to SHAs were completely unaffected.
GitHub's own security hardening guide recommends SHA pinning as "the only way to use an action as an immutable release."
Actions to pin
In
release.yml:azure/login@v2azure/artifact-signing-action@v1actions/checkout@v4actions/upload-artifact@v4actions/download-artifact@v4Other workflow files (e.g.,
ci.yml) should also be updated for consistency.Implementation
uses:line withuses: owner/action@<full-sha> # <version-tag>.github/dependabot.ymlto automatically update pinned SHAs:References