No Hash Pinning

Description

Workflows that pin actions to version tags (e.g., @v1, @v2.0.0) instead of commit SHAs are vulnerable to supply-chain attacks: tags are mutable—maintainers can move them to different commits, delete and recreate them, or attackers who compromise a repository can redirect tags to malicious code. Your workflow would then automatically use the compromised version on the next run. Commit SHA hashes are immutable and provide guaranteed integrity. 1

Vulnerable Instance

  • Workflow uses a version tag like actions/checkout@v4 instead of a commit SHA.
  • If the repository is compromised, an attacker could move the v4 tag to point to malicious code.
  • The workflow would automatically pull the malicious version on the next run.
name: CI
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4              # mutable — tag can be moved
      - uses: actions/setup-node@v4            # mutable — tag can be moved
        with:
          node-version: 20
      - uses: actions/upload-artifact@v4       # mutable — tag can be moved
        with:
          name: dist
          path: dist/

Mitigation Strategies

  1. Pin to full commit SHA
    Replace tags with the full 40-character commit SHA (e.g., actions/checkout@8f4b7f84884ec3e152e95e913f196d7a537752ca). SHAs are immutable and cannot be changed.

  2. Find the SHA for a tag
    Visit https://github.com/{owner}/{repo}/releases/tag/{tag} or use GitHub CLI: gh api repos/{owner}/{repo}/git/refs/tags/{tag} | jq -r .object.sha

  3. Verify SHA correctness
    Ensure the SHA is exactly 40 hexadecimal characters. Verify by visiting https://github.com/{owner}/{repo}/commit/{sha}.

  4. Automate SHA updates
    Use tools like Dependabot or Renovate to suggest SHA updates when new releases are available, but review changes before merging.

  5. Audit existing workflows
    Periodically scan all workflows for tag-based pinning and migrate to SHAs. Consider using automated tooling to detect and report unpinned actions.

  6. Document pinning policy
    Establish team guidelines requiring SHA pinning for all third-party actions, especially those with write permissions or access to secrets.

Secure Version

Replace every mutable tag with the full 40-character commit SHA. Append a comment with the original tag so humans can tell what version is pinned:

 name: CI
 on: [push]
 jobs:
   build:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2
-      - uses: actions/setup-node@v4
+      - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020  # v4.4.0
         with:
           node-version: 20
-      - uses: actions/upload-artifact@v4
+      - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02  # v4.6.2
         with:
           name: dist
           path: dist/

To look up the SHA for any tag yourself:

gh api repos/actions/checkout/git/refs/tags/v4.2.2 --jq '.object.sha'
# → 11bd71901bbe5b1630ceea73d27597364c9af683

Impact

DimensionSeverityNotes
LikelihoodHighTag-based pinning is extremely common, and repository compromises or maintainer mistakes can redirect tags.
RiskHighCompromised actions can steal secrets, modify code, or deploy backdoors with the workflow’s permissions.
Blast radiusWideAll workflows using the compromised action are affected, potentially impacting all CI/CD pipelines and deployments.

References



  1. GitHub Docs, “Security hardening for GitHub Actions - Using actions,” https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-actions ↩︎ ↩︎

Last updated on