Agent skill
action-pinning-overview
Why pinning GitHub Actions to SHA-256 commits matters for supply chain security. Attack vectors from unpinned actions and comparison of tag vs SHA pinning.
Install this agent skill to your Project
npx add-skill https://github.com/adaptive-enforcement-lab/claude-skills/tree/main/plugins/secure/skills/action-pinning-overview
SKILL.md
Action Pinning Overview
When to Use This Skill
Lock down your GitHub Actions supply chain. Unpinned actions are the fastest route to a compromised CI/CD pipeline.
The Risk
Every action in your workflow executes with access to your repository secrets, cloud credentials, and deployment permissions. A single compromised action can exfiltrate everything.
Why Action Pinning Matters
GitHub Actions workflows pull third-party code directly into your CI/CD pipeline. Without pinning, you're trusting that:
- The action maintainer won't turn malicious
- Their account won't be compromised
- Their repository won't be hijacked
- Tag references won't be moved to malicious commits
Reality: All four scenarios have occurred in production environments.
The Attack Surface
flowchart TD
A["Unpinned Action<br/>uses: actions/checkout@v4"] --> B["Tag Reference"]
B --> C{"Maintainer Updates Tag"}
C -->|Legitimate Update| D["New Features"]
C -->|Compromised Account| E["Malicious Code"]
C -->|Hijacked Repo| F["Backdoor Injection"]
E --> G["Exfiltrate Secrets"]
E --> H["Deploy Backdoor"]
E --> I["Modify Code"]
F --> G
F --> H
F --> I
%% Ghostty Hardcore Theme
style A fill:#f92572,color:#1b1d1e
style B fill:#fd971e,color:#1b1d1e
style C fill:#e6db74,color:#1b1d1e
style D fill:#a6e22e,color:#1b1d1e
style E fill:#f92572,color:#1b1d1e
style F fill:#f92572,color:#1b1d1e
style G fill:#66d9ef,color:#1b1d1e
style H fill:#66d9ef,color:#1b1d1e
style I fill:#66d9ef,color:#1b1d1e
Tag References vs SHA Pinning
Tag-Based References (Unsafe)
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
The Problem: Tags are mutable. Maintainers can update v4 to point to any commit. You have no guarantee the code hasn't changed since you tested it.
Attack Vector: Compromised maintainer moves tag to malicious commit. Every workflow using that tag now executes attacker code.
SHA Pinning (Secure)
# actions/checkout v4.1.1
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
# actions/setup-node v3.8.1
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d
The Defense: SHA-256 commit hashes are immutable. The code at that hash cannot change. You're pinning to exact, verified code.
Comment Strategy: Include the semantic version in a comment so humans know what SHA represents.
Tag vs SHA Comparison
| Aspect | Tag Reference | SHA Pinning |
|---|---|---|
| Mutability | Tag can move to any commit | SHA is immutable |
| Supply Chain Risk | High - trust maintainer forever | Low - trust specific commit |
| Update Visibility | Silent updates | Explicit updates via PR |
| Compromise Detection | Difficult - looks like normal update | Clear - SHA change triggers review |
| Dependabot Support | Yes | Yes |
| Human Readability | Good (v4) |
Poor (b4ffde6...) without comments |
| Security Posture | Vulnerable | Hardened |
Real-World Attack Scenarios
Scenario 1: Compromised Maintainer Account
Timeline:
- T+0: Attacker compromises maintainer's GitHub account via credential stuffing
- T+1h: Attacker updates
v3tag to point to backdoored commit - T+2h: Thousands of workflows worldwide execute malicious code
- T+6h: Secrets exfiltrated to attacker-controlled servers
- T+24h: Breach discovered, tag reverted, damage done
Impact: Multi-organization breach. Secrets, credentials, and source code compromised across hundreds of repositories.
Prevention: SHA pinning. Workflows continue using verified commit. Dependabot flags the tag update for review.
Scenario 2: Repository Takeover
Timeline:
- T+0: Popular action repository uses simple password, no 2FA
- T+1d: Attacker gains access, adds malicious code to next release
- T+2d: Users update to new version via tag reference
- T+3d: Backdoor establishes persistence in CI/CD pipelines
- T+7d: Attacker pivots to production deployments
Impact: Supply chain compromise affecting downstream users. Deployment credentials stolen, production systems compromised.
Prevention: SHA pinning with Dependabot review. Team reviews changelog and diff before approving SHA update.
Scenario 3: Typosquatting with Tag Manipulation
Timeline:
- T+0: Attacker creates
actions/check0ut(zero instead of 'o') - T+1h: Developer makes typo in workflow file
- T+2h: Malicious action executes with repository secrets
- T+3h: AWS credentials exfiltrated
- T+4h: Attacker deploys crypto miners to organization's cloud account
Impact: Developer typo leads to cloud account compromise. Thousands in cloud costs, potential data breach.
Prevention: SHA pinning forces explicit review. Full action path visible in security review. Allowlisting blocks unknown actions.
Supply Chain Risk Framework
Trust Tiers
Tier 1: GitHub-Maintained Actions
- Examples:
actions/checkout,actions/setup-node,actions/upload-artifact - Risk: Low (GitHub's security team)
- Recommendation: SHA pin, but lower review priority
Tier 2: Verified Publishers
- Examples:
aws-actions/*,azure/*,google-github-actions/* - Risk: Medium (corporate security teams)
- Recommendation: SHA pin, review on updates
Tier 3: Community Actions
- Examples: Individual maintainers, small teams
- Risk: High (unknown security posture)
- Recommendation: SHA pin, thorough source review, consider forking
Tier 4: Unknown/Unvetted
- Risk: Critical
- Recommendation: Block until reviewed, consider alternatives
Attack Vector Deep Dive
1. Tag Mutation Attack
Mechanism: Attacker with write access moves tag to malicious commit.
# Attacker commands
git tag -d v3
git tag v3 <malicious-commit-sha>
git push --force --tags
Result: All workflows using @v3 now execute malicious code. No PR, no review, no notification.
2. Dependency Confusion
Mechanism: Action imports malicious package via package manager inside action code.
Example:
# Action looks safe
- uses: trusted-org/deploy-action@v2
But inside trusted-org/deploy-action:
// action.js imports compromised package
const utils = require('internal-deploy-utils'); // Typosquatted package
Result: Even SHA-pinned action can be compromised if it pulls unpinned dependencies.
Defense: Review action source code, check action's own dependencies, use Dependabot for action repos.
3. Compromised GitHub Account
Mechanism: Attacker uses stolen credentials or session hijacking to access maintainer account.
Attack Path:
- Phishing email targets maintainer
- Credentials harvested
- Attacker logs in (no 2FA required)
- Malicious commit pushed
- Tag updated
- Backdoor deployed to thousands of workflows
Result: Widespread compromise across all users of the action.
Defense: SHA pinning breaks attack chain. Workflows don't auto-update to compromised version.
Pinning Strategy
Baseline Security Posture
name: Secure CI
on: [push]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
# SHA-pinned actions with version comments
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
Update Workflow with Dependabot
Dependabot monitors your workflow files and creates PRs for action updates:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- "dependencies"
- "github-actions"
Process:
- Dependabot detects new action version
- Creates PR updating SHA with version comment
- Team reviews changelog and diff
- Approve or reject update
- Merge updates approved changes
Exceptions and Trade-offs
When SHA Pinning May Not Apply
Internal Actions (same organization):
# Internal shared action
- uses: my-org/shared-workflows/.github/actions/deploy@main
Consideration: If you control the repository and trust your team, tag references acceptable. Still recommend SHA pinning for audit trail.
Docker Container Actions:
# Action runs in container
- uses: docker://alpine:3.18
Consideration: Container images have their own pinning strategy (digest-based). Apply same principles:
# Digest-pinned container
- uses: docker://alpine@sha256:abc123...
Integration with Security Controls
1. Action Allowlisting
Organization-level policy restricts which actions can be used:
Settings → Actions → General → Allow select actions and reusable workflows
Add verified actions to allowlist. Blocks unknown actions at workflow runtime.
2. Branch Protection
Require status checks for workflows that modify action pins:
- Enforce code review for
.github/workflows/*changes - Require security team approval for new actions
- Block force pushes to protected branches
3. Audit and Monitoring
Track action usage across organization:
- Audit log: Filter by
workflow_job - SIEM integration: Alert on new action patterns
- Periodic reviews: Quarterly action security audit
Next Steps
Ready to implement SHA pinning? Continue with:
- SHA Pinning Patterns: Complete implementation patterns with copy-paste examples
- Automation Scripts: Detect unpinned actions, bulk update to SHAs, verify pins
- Dependabot Configuration: Automated updates with security review workflow
Quick Reference
| Risk | Mitigation | Effort |
|---|---|---|
| Tag mutation | SHA pinning | Low |
| Compromised maintainer | SHA pinning + review | Medium |
| Typosquatting | Allowlisting | Medium |
| Dependency confusion | Source review | High |
| Silent updates | Dependabot + PR review | Low |
Start Today
Pin your most critical workflows first. Focus on workflows with:
- Production deployment access
- Cloud credential usage
- Cross-repository permissions
Use automation scripts to detect unpinned actions and generate SHA-pinned versions.
When to Apply
Scenario 1: Compromised Maintainer Account
Timeline:
- T+0: Attacker compromises maintainer's GitHub account via credential stuffing
- T+1h: Attacker updates
v3tag to point to backdoored commit - T+2h: Thousands of workflows worldwide execute malicious code
- T+6h: Secrets exfiltrated to attacker-controlled servers
- T+24h: Breach discovered, tag reverted, damage done
Impact: Multi-organization breach. Secrets, credentials, and source code compromised across hundreds of repositories.
Prevention: SHA pinning. Workflows continue using verified commit. Dependabot flags the tag update for review.
Scenario 2: Repository Takeover
Timeline:
- T+0: Popular action repository uses simple password, no 2FA
- T+1d: Attacker gains access, adds malicious code to next release
- T+2d: Users update to new version via tag reference
- T+3d: Backdoor establishes persistence in CI/CD pipelines
- T+7d: Attacker pivots to production deployments
Impact: Supply chain compromise affecting downstream users. Deployment credentials stolen, production systems compromised.
Prevention: SHA pinning with Dependabot review. Team reviews changelog and diff before approving SHA update.
Scenario 3: Typosquatting with Tag Manipulation
Timeline:
- T+0: Attacker creates
actions/check0ut(zero instead of 'o') - T+1h: Developer makes typo in workflow file
- T+2h: Malicious action executes with repository secrets
- T+3h: AWS credentials exfiltrated
- T+4h: Attacker deploys crypto miners to organization's cloud account
Impact: Developer typo leads to cloud account compromise. Thousands in cloud costs, potential data breach.
Prevention: SHA pinning forces explicit review. Full action path visible in security review. Allowlisting blocks unknown actions.
Implementation
See the full implementation guide in the source documentation.
Comparison
Tag-Based References (Unsafe)
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
The Problem: Tags are mutable. Maintainers can update v4 to point to any commit. You have no guarantee the code hasn't changed since you tested it.
Attack Vector: Compromised maintainer moves tag to malicious commit. Every workflow using that tag now executes attacker code.
SHA Pinning (Secure)
# actions/checkout v4.1.1
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
# actions/setup-node v3.8.1
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d
The Defense: SHA-256 commit hashes are immutable. The code at that hash cannot change. You're pinning to exact, verified code.
Comment Strategy: Include the semantic version in a comment so humans know what SHA represents.
Examples
See examples.md for code examples.
Full Reference
See reference.md for complete documentation.
References
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
github-token-permissions-overview
Understanding GITHUB_TOKEN scope, default permissions, and implementing least-privilege principle for GitHub Actions workflows.
secure
Find and fix security issues before they become incidents. Vulnerability scanning, SBOM generation, supply chain security, and secure authentication workflows.
complete-workflow-examples
Copy-paste hardened CI/CD workflows with SHA-pinned actions, minimal GITHUB_TOKEN permissions, OIDC authentication, and comprehensive security scanning for GitHub Actions.
ephemeral-runner-patterns
Disposable runner patterns for GitHub Actions. Container-based, VM-based, and ARC deployment strategies with complete state isolation between jobs.
github-actions-security-patterns-hub
Complete security patterns for GitHub Actions covering action pinning, GITHUB_TOKEN permissions, third-party action risks, secret management, and runner security.
security-scanning-workflows
Comprehensive security scanning examples with SAST (CodeQL), dependency scanning, container vulnerability detection (Trivy), and SARIF upload to GitHub Security tab.
Didn't find tool you were looking for?