Unsafe Checkout Ref
Description
Workflows that use actions/checkout with refs containing variables that may not be properly validated create security risks: if the ref comes from user input (workflow_dispatch, pull_request), attackers could checkout arbitrary branches or commits, malicious code could be executed from untrusted refs, and secrets could be exposed if checking out untrusted code. Refs should be validated against allowlists before use. 1
Vulnerable Instance
- Workflow uses
actions/checkoutwith a ref from user input without validation. - Ref could point to malicious code or branches.
- Attackers can checkout arbitrary branches or commits.
name: Build from Ref
on:
workflow_dispatch:
inputs:
branch:
type: string
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.branch }} # Dangerous - unvalidated user input
- run: npm testMitigation Strategies
Validate refs against an allowlist
Validate refs before using them in checkout. Only allow specific branches or patterns that are safe.Use fixed refs when possible
Use fixed refs likerefs/heads/maininstead of user-controlled variables when the branch is known.For pull requests, checkout the base branch
Usegithub.event.pull_request.base.refinstead of the PR branch to avoid checking out untrusted code from forks.Sanitize ref inputs
Sanitize ref inputs before use. Reject refs that don’t match expected patterns or contain suspicious characters.Review all checkout refs
Audit all workflows for checkout steps with user-controlled refs. Ensure all refs are validated.Use branch protection
Use branch protection rules to prevent direct pushes to protected branches. Require pull requests for changes.
Secure Version
name: Build from Ref
on:
workflow_dispatch:
inputs:
branch:
- type: string
+ type: choice
+ options: [main, develop] # Restricted choices
jobs:
build:
runs-on: ubuntu-latest
steps:
+ - name: Validate ref
+ run: |
+ if [[ "${{ inputs.branch }}" != "main" && "${{ inputs.branch }}" != "develop" ]]; then
+ echo "Invalid branch"
+ exit 1
+ fi
- uses: actions/checkout@v4
with:
- ref: ${{ inputs.branch }} # Dangerous - unvalidated user input
+ ref: refs/heads/${{ inputs.branch }} # Validated
- run: npm test
Impact
| Dimension | Severity | Notes |
|---|---|---|
| Likelihood | Unvalidated checkout refs are less common but create high risk when present, especially with user input. | |
| Risk | Attackers can checkout malicious branches or commits, enabling code injection, secret exfiltration, or system compromise. | |
| Blast radius | Compromised code from untrusted refs can affect all systems the workflow can access, including repositories, secrets, and deployment targets. |
References
- GitHub Docs, “actions/checkout,” https://github.com/actions/checkout 1
GitHub Docs, “actions/checkout,” https://github.com/actions/checkout ↩︎ ↩︎