Introduction
The file src/negative_test/github-workflow/bad_pull_request_event_declaration.yaml contained a subtle but dangerous security flaw at line 11. While the workflow appeared to simply check out repository code using the popular actions/checkout action, the reference @v1 created a supply-chain attack vector that could allow malicious code to execute in your CI/CD pipeline without any changes to your repository.
This isn't theoretical—real-world compromises of GitHub Actions like trivy-action and kics-github-action have demonstrated how attackers exploit mutable tags to inject malicious code into thousands of downstream repositories. When you reference actions/checkout@v1, you're trusting that whoever controls that tag will never—intentionally or through compromise—point it at malicious code.
The Vulnerability Explained
When you write a GitHub Actions workflow step like this:
steps:
- uses: actions/checkout@v1
You're telling GitHub "go fetch whatever code is currently tagged as v1 from the actions/checkout repository and run it." The critical word here is currently—that tag can change at any time.
How Tags Work in Git
Git tags are just pointers to commits. While they're often treated as immutable version markers, they can be deleted and recreated to point at different commits. This means:
- Today,
actions/checkout@v1might point to commitabc123 - Tomorrow, the repository owner (or an attacker who compromises their account) could repoint it to commit
xyz789 - Your workflow would silently start running completely different code
Attack Scenario for This Workflow
Consider this specific workflow file handling pull request events:
name: bad_pull_request_event_declaration
on:
pull_request:
jobs:
with:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
An attacker who gains access to the actions/checkout repository could:
- Modify the code that runs during checkout to exfiltrate secrets
- Repoint the
v1tag to their malicious commit - Wait for any pull request to trigger this workflow
- Harvest
GITHUB_TOKEN, repository secrets, or inject backdoors into builds
The workflow would continue to show uses: actions/checkout@v1—no visible change—while executing completely different code.
Real-World Precedent
This isn't hypothetical. In 2023, the tj-actions/changed-files action was compromised when an attacker gained access and modified the action to steal secrets from CI runs. Organizations using mutable tags were affected; those using pinned SHAs were protected.
The Fix
The fix replaces the mutable tag reference with an immutable commit SHA:
Before (Vulnerable)
steps:
- uses: actions/checkout@v1
After (Secure)
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
Why This Works
The 40-character SHA 11bd71901bbe5b1630ceea73d27597364c9af683 is a cryptographic hash of a specific commit. It cannot be repointed—it's mathematically tied to that exact code. If an attacker modifies the action code, the resulting commit would have a completely different SHA.
The trailing comment # v4.2.2 serves as documentation, making it easy for developers to understand which version is pinned without the SHA being human-readable.
Additional Improvements
Note that the fix also upgrades from v1 to v4.2.2. This brings security improvements, bug fixes, and better performance from three major versions of development—while ensuring the exact code is locked to a verified commit.
Prevention & Best Practices
1. Always Pin to Full Commit SHAs
For every GitHub Action in your workflows:
# ❌ Vulnerable - mutable tag
- uses: actions/setup-node@v4
# ❌ Still vulnerable - branches are mutable
- uses: actions/setup-node@main
# ✅ Secure - immutable SHA
- uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
2. Use Dependabot or Renovate
Configure automated dependency updates to keep your pinned SHAs current while maintaining security:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
3. Audit Existing Workflows
Run Semgrep or similar tools to find mutable references:
semgrep --config "p/github-actions" .github/workflows/
4. Verify SHAs Before Pinning
When pinning a new action:
1. Visit the action's repository
2. Navigate to the release/tag you want
3. Copy the full commit SHA from the release
4. Verify the commit is signed if possible
Key Takeaways
- The
actions/checkout@v1pattern inbad_pull_request_event_declaration.yamlwas a supply-chain attack vector that could execute arbitrary code in CI without any visible workflow changes - Commit SHA
11bd71901bbe5b1630ceea73d27597364c9af683is cryptographically immutable—unlike tags, it cannot be silently repointed to malicious code - Pull request event workflows are high-value targets because they often have access to repository secrets and can modify code during builds
- Adding version comments like
# v4.2.2maintains readability while preserving the security benefits of SHA pinning - This defensive hardening removes an exploit primitive that automated attack tools could chain with other weaknesses
How Orbis AppSec Detected This
- Source: External GitHub Action repository referenced in workflow
- Sink:
uses: actions/checkout@v1insrc/negative_test/github-workflow/bad_pull_request_event_declaration.yaml:11 - Missing control: No immutable reference (commit SHA) to verify action integrity
- CWE: CWE-829 (Inclusion of Functionality from Untrusted Control Sphere)
- Fix: Replaced mutable tag
@v1with immutable commit SHA@11bd71901bbe5b1630ceea73d27597364c9af683
Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.
Conclusion
Supply-chain security in CI/CD pipelines is increasingly critical as attackers target the software build process. The simple change from actions/checkout@v1 to actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 transforms a workflow from "trusting the internet" to "trusting cryptographically verified code."
This pattern applies to every GitHub Action in your workflows. Take time to audit your existing workflow files, pin all actions to commit SHAs, and set up automated tooling to keep those pins updated. Your future self—and your security team—will thank you.