Unlike npm and PyPI, GitHub Actions tags are mutable. A maintainer — or an attacker
with their credentials — can silently replace what v3 points to. Every workflow
using tag-based references is one compromised account away from leaking every secret in the pipeline.
reviewdog/action-setup. The malicious commit replaced the action's tag, dumping CI/CD
secrets to workflow logs. 23,000 repos used the action; 218 repos
had secrets exposed including AWS keys, DockerHub credentials, and npm tokens. The attack lasted
~22 hours before detection.
| npm / PyPI | GitHub Actions | |
|---|---|---|
| Version immutability | Immutable (once published, can't change) | Mutable (tags can be silently replaced) |
| Execution context | Runs in your app's sandbox | Runs in CI with secrets, tokens, deploy keys |
| Attack surface | Code injection at build/runtime | Direct access to GITHUB_TOKEN + all workflow secrets |
| Mitigation | Lockfiles pin exact versions | SHA pinning available but rarely used |
| # | Action | Risk | Score | Repos using | Owner | Permissions |
|---|
Most supply chain monitoring focuses on packages. But the CI/CD pipeline is often the highest-privilege environment in the entire software lifecycle — it has deploy keys, cloud credentials, and signing keys. A compromised Action is not a dependency risk. It is a credential exfiltration risk.
Trust score combines owner trust (GitHub official vs solo dev), permissions scope (read-only vs secrets access), adoption scale (blast radius if compromised), and incident history. Actions run by solo developers with write permissions and massive usage are the highest-value targets.
Replace uses: org/action@v4 with
uses: org/action@SHA # v4.x.x. Tools like
pin-github-action
automate this. It takes 5 minutes to pin every Action in your workflows.
After the tj-actions incident, there is no excuse.