Supply Chain Security Checks¶
Key Insight
Pinning dependencies prevents unexpected malicious updates.
Critical checks that protect against supply chain attacks. These have the highest security impact and should be prioritized first.
Covered checks:
- Pinned-Dependencies: Pin dependencies to SHA digests
- Dangerous-Workflow: Prevent workflow-based attacks
- Binary-Artifacts: Remove binaries from source control
- SAST: Static application security testing
Weight: High. These checks prevent real supply chain attacks.
Pinned-Dependencies¶
Target: 10/10 by pinning all GitHub Actions to SHA digests
What it checks: Whether dependencies (GitHub Actions, containers, third-party tools) are pinned to immutable references.
Why it matters: Version tags are mutable. actions/checkout@v4 can change behavior overnight. SHA digests are immutable and prevent unexpected code execution.
Understanding the Score¶
Scorecard analyzes:
- GitHub Actions references in
.github/workflows/*.yml - Container image references in Dockerfiles
- Installation scripts that download dependencies
Scoring:
- 10/10: All dependencies pinned to SHA digests
- 8/10: Most actions pinned, minor exceptions
- 5/10: Mix of version tags and SHA pins
- 0/10: No SHA pinning
Before: Version Tags (Mutable)¶
name: Release
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # Tag can be moved
- uses: actions/setup-go@v5 # Tag can be moved
Risk: Action maintainer can update v4 tag to point to malicious code. Your workflow automatically pulls the compromised version.
After: SHA Pins (Immutable)¶
name: Release
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
Protection: SHA digest is cryptographically immutable. Even if action is compromised, you run known-good code.
Legitimate Exceptions¶
Some actions require version tags and will fail with SHA pins:
Exception 1: ossf/scorecard-action¶
# MUST use version tag. Action verifies its own workflow identity
- uses: ossf/scorecard-action@v2.4.0
Reason: Internal workflow verification requires version tag for identity validation.
Exception 2: slsa-framework/slsa-github-generator¶
# MUST use version tag. Verifier validates builder by tag
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0
Reason: SLSA verifier checks builder identity against known version tags. SHA references fail cryptographic verification.
Automated Pinning with Renovate¶
Recommended: Let Renovate handle pinning automatically.
Create .github/renovate.json:
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"],
"packageRules": [
{
"description": "Auto-pin GitHub Actions to SHA digests",
"matchManagers": ["github-actions"],
"pinDigests": true
},
{
"description": "Exceptions that require version tags",
"matchManagers": ["github-actions"],
"matchPackageNames": [
"ossf/scorecard-action",
"slsa-framework/slsa-github-generator"
],
"pinDigests": false,
"extractVersion": "^(?<version>v\\d+\\.\\d+\\.\\d+)$"
}
]
}
Result: Renovate automatically:
- Pins all actions to SHA digests with version comment
- Creates PRs when new versions are available
- Preserves version tags for documented exceptions
Manual Pinning¶
If you can't use Renovate:
# Find SHA for a specific version
gh api repos/actions/checkout/git/ref/tags/v4.1.1 --jq .object.sha
# Result: b4ffde65f46336ab88eb53be808477a3936bae11
Format:
Always include version comment. Humans need to understand which version the SHA represents.
Container Images¶
Pin container images to SHA digests too:
# Before (mutable tag)
FROM golang:1.21
# After (immutable digest)
FROM golang:1.21@sha256:4746d26432a9117a5f58e95cb9f954ddf0de128e9d5816886514199316e4a2fb
Third-Party Installation Scripts¶
Pin download URLs to specific versions:
# Before (latest, mutable)
- run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh
# After (pinned version)
- run: |
curl -sSfL https://github.com/golangci/golangci-lint/releases/download/v1.55.2/golangci-lint-1.55.2-linux-amd64.tar.gz \
-o golangci-lint.tar.gz
echo "ca21c961a33be3bc15e4292dc40c98c8dcc5463a7b6768a3afc123761630c09c golangci-lint.tar.gz" | sha256sum -c -
tar -xzf golangci-lint.tar.gz
Add checksum verification to prevent tampering during download.
Troubleshooting¶
Pinned-Dependencies still flagging exceptions¶
Expected: Scorecard will flag ossf/scorecard-action and slsa-framework/slsa-github-generator.
Action: Document exceptions in repository README or PR descriptions. Scorecard score reflects reality. Some tools don't support SHA pinning.
Renovate not creating SHA pin PRs¶
Check: Is pinDigests: true in Renovate config?
Check: Does Renovate have write access to repository?
How do I find the SHA for a version tag?¶
# GitHub CLI
gh api repos/OWNER/REPO/git/ref/tags/VERSION --jq .object.sha
# Web UI
# Go to https://github.com/OWNER/REPO/releases
# Click on version tag → Commits → Copy SHA