OpenSSF Scorecard Cheat Sheet
Overview
OpenSSF Scorecard is an automated tool from the Open Source Security Foundation that assesses the security posture of open-source projects hosted on GitHub. It runs a series of checks that evaluate security practices including code review enforcement, branch protection, dependency management, fuzzing, SAST usage, vulnerability disclosure processes, and CI/CD security. Each check produces a score from 0 to 10, and the aggregate score helps organizations make informed decisions about the security risk of their dependencies.
Scorecard is critical for software supply chain security, helping organizations identify which open-source dependencies follow security best practices and which may pose risks. It can be integrated into CI/CD pipelines to continuously monitor your own repositories against security standards, and the results can be published to the OpenSSF Scorecard API for public visibility. The tool supports GitHub Actions integration for automated weekly scanning and issue creation.
Installation
CLI Installation
# macOS
brew install scorecard
# Linux
curl -fsSL https://github.com/ossf/scorecard/releases/latest/download/scorecard-linux-amd64 \
-o /usr/local/bin/scorecard
chmod +x /usr/local/bin/scorecard
# Go install
go install github.com/ossf/scorecard/v5/cmd/scorecard@latest
# Docker
docker pull gcr.io/openssf/scorecard:latest
# Verify installation
scorecard version
Authentication Setup
# Scorecard requires a GitHub token for API access
export GITHUB_AUTH_TOKEN="ghp_your_github_token"
# For higher rate limits, use a GitHub App
export GITHUB_APP_ID="app-id"
export GITHUB_APP_INSTALLATION_ID="installation-id"
export GITHUB_APP_PRIVATE_KEY_PATH="/path/to/private-key.pem"
# Verify authentication
scorecard --repo github.com/ossf/scorecard --checks Token-Permissions
Core Commands
Scanning Repositories
# Scan a repository (all checks)
scorecard --repo github.com/kubernetes/kubernetes
# Scan with specific output format
scorecard --repo github.com/kubernetes/kubernetes --format json > results.json
scorecard --repo github.com/kubernetes/kubernetes --format sarif > results.sarif
scorecard --repo github.com/kubernetes/kubernetes --format default
# Scan specific checks only
scorecard --repo github.com/kubernetes/kubernetes \
--checks Code-Review,Branch-Protection,Signed-Releases
# Scan a local repository
scorecard --local .
# Scan with verbose output
scorecard --repo github.com/kubernetes/kubernetes --show-details
# Scan and output to file
scorecard --repo github.com/kubernetes/kubernetes \
--format json \
--output results.json
# Docker scan
docker run -e GITHUB_AUTH_TOKEN="$GITHUB_AUTH_TOKEN" \
gcr.io/openssf/scorecard:latest \
--repo github.com/kubernetes/kubernetes --format json
Available Checks
| Check | Description | Score Range |
|---|---|---|
| Binary-Artifacts | No binary artifacts in source | 0-10 |
| Branch-Protection | Branch protection rules enabled | 0-10 |
| CI-Tests | CI tests run on commits | 0-10 |
| CII-Best-Practices | CII Best Practices badge | 0-10 |
| Code-Review | Code changes are reviewed | 0-10 |
| Contributors | Project has multiple contributors | 0-10 |
| Dangerous-Workflow | No dangerous patterns in CI | 0-10 |
| Dependency-Update-Tool | Uses dependency update tools | 0-10 |
| Fuzzing | Project uses fuzzing | 0-10 |
| License | Has an OSS license | 0-10 |
| Maintained | Project is actively maintained | 0-10 |
| Packaging | Published as a package | 0-10 |
| Pinned-Dependencies | Dependencies pinned by hash | 0-10 |
| SAST | Uses static analysis tools | 0-10 |
| Security-Policy | Has SECURITY.md | 0-10 |
| Signed-Releases | Releases are signed | 0-10 |
| Token-Permissions | CI tokens use least privilege | 0-10 |
| Vulnerabilities | No known vulnerabilities | 0-10 |
| Webhooks | Webhooks use secrets | 0-10 |
# Run specific checks
scorecard --repo github.com/org/repo --checks Branch-Protection
scorecard --repo github.com/org/repo --checks Code-Review,CI-Tests,SAST
scorecard --repo github.com/org/repo --checks Vulnerabilities,Dependency-Update-Tool
# List all available checks
scorecard --repo github.com/org/repo --checks "" 2>&1 | grep "check"
Querying the Public API
# Check score for popular projects via the API
curl -s "https://api.securityscorecards.dev/projects/github.com/kubernetes/kubernetes" | jq '{
repo: .repo.name,
score: .score,
date: .date,
checks: [.checks[] | {name, score, reason}]
}'
# Get specific check details
curl -s "https://api.securityscorecards.dev/projects/github.com/kubernetes/kubernetes" \
| jq '.checks[] | select(.name == "Branch-Protection") | {name, score, reason, details}'
# List projects with scores above threshold
curl -s "https://api.securityscorecards.dev/projects/github.com/golang/go" \
| jq '{score, checks: [.checks[] | select(.score >= 8) | {name, score}]}'
Configuration
GitHub Actions Integration
# .github/workflows/scorecard.yml
name: OpenSSF Scorecard
on:
# Run on any branch protection rule change
branch_protection_rule:
# Run weekly
schedule:
- cron: '0 6 * * 1'
push:
branches: [main]
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
security-events: write
id-token: write
contents: read
actions: read
steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Run Scorecard
uses: ossf/scorecard-action@v2
with:
results_file: results.sarif
results_format: sarif
publish_results: true
# Optionally filter checks
# checks: 'Code-Review,Branch-Protection,Signed-Releases'
- name: Upload to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: scorecard-results
path: results.sarif
SARIF Output for Security Tools
# Generate SARIF for GitHub Code Scanning
scorecard --repo github.com/org/repo \
--format sarif \
--output scorecard-results.sarif
# Upload to GitHub Code Scanning via API
curl -X POST \
"https://api.github.com/repos/ORG/REPO/code-scanning/sarifs" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"commit_sha\": \"$(git rev-parse HEAD)\",
\"ref\": \"refs/heads/main\",
\"sarif\": \"$(gzip -c scorecard-results.sarif | base64 -w0)\"
}"
Policy Enforcement
#!/bin/bash
# scorecard-gate.sh — CI quality gate based on Scorecard
set -euo pipefail
REPO="${1:-github.com/org/repo}"
MIN_SCORE="${2:-7}"
echo "Running Scorecard for $REPO (minimum score: $MIN_SCORE)..."
RESULTS=$(scorecard --repo "$REPO" --format json 2>/dev/null)
OVERALL_SCORE=$(echo "$RESULTS" | jq '.aggregate_score')
echo "Overall Score: $OVERALL_SCORE / 10"
# Check critical checks
CRITICAL_CHECKS=("Branch-Protection" "Code-Review" "Vulnerabilities" "Token-Permissions")
FAILED=false
for check in "${CRITICAL_CHECKS[@]}"; do
SCORE=$(echo "$RESULTS" | jq -r ".checks[] | select(.name == \"$check\") | .score")
STATUS="PASS"
if [ "$SCORE" -lt "$MIN_SCORE" ]; then
STATUS="FAIL"
FAILED=true
fi
printf " %-30s Score: %2s [%s]\n" "$check" "$SCORE" "$STATUS"
done
echo ""
if [ "$FAILED" = true ]; then
echo "FAILED: One or more critical checks below minimum score of $MIN_SCORE"
exit 1
fi
if (( $(echo "$OVERALL_SCORE < $MIN_SCORE" | bc -l) )); then
echo "FAILED: Overall score $OVERALL_SCORE below minimum $MIN_SCORE"
exit 1
fi
echo "PASSED: All security checks meet minimum requirements"
Advanced Usage
Batch Scanning Multiple Repos
#!/bin/bash
# batch-scan.sh — Scan all repos in an organization
ORG="your-org"
OUTPUT_DIR="scorecard-results"
mkdir -p "$OUTPUT_DIR"
# Get all repos via GitHub API
REPOS=$(curl -s -H "Authorization: Bearer $GITHUB_AUTH_TOKEN" \
"https://api.github.com/orgs/$ORG/repos?per_page=100&type=sources" \
| jq -r '.[].full_name')
echo "Scanning $(echo "$REPOS" | wc -l) repositories..."
for repo in $REPOS; do
echo "Scanning: $repo"
scorecard --repo "github.com/$repo" --format json \
> "$OUTPUT_DIR/$(echo "$repo" | tr '/' '-').json" 2>/dev/null || true
sleep 2 # Rate limiting
done
# Generate summary report
echo "Repository,Score,Branch-Protection,Code-Review,Vulnerabilities" > "$OUTPUT_DIR/summary.csv"
for file in "$OUTPUT_DIR"/*.json; do
REPO=$(jq -r '.repo.name' "$file")
SCORE=$(jq -r '.aggregate_score' "$file")
BP=$(jq -r '.checks[] | select(.name=="Branch-Protection") | .score' "$file")
CR=$(jq -r '.checks[] | select(.name=="Code-Review") | .score' "$file")
VU=$(jq -r '.checks[] | select(.name=="Vulnerabilities") | .score' "$file")
echo "$REPO,$SCORE,$BP,$CR,$VU" >> "$OUTPUT_DIR/summary.csv"
done
echo "Results saved to $OUTPUT_DIR/summary.csv"
Dependency Scorecard Assessment
#!/bin/bash
# dep-scores.sh — Score all direct dependencies
# Requires: go (for Go projects) or package.json analysis
# For Go projects
go list -m -json all | jq -r 'select(.Main != true) | .Path' | while read dep; do
# Convert Go module path to GitHub repo
repo=$(echo "$dep" | sed 's|^golang.org/x/|github.com/golang/|;s|^google.golang.org/|github.com/googleapis/|')
if [[ "$repo" == github.com/* ]]; then
SCORE=$(scorecard --repo "$repo" --format json 2>/dev/null | jq '.aggregate_score // "N/A"')
echo "$dep: $SCORE"
fi
done
# For npm projects
jq -r '.dependencies // {} | keys[]' package.json | while read pkg; do
# Look up repo from npm registry
REPO=$(curl -s "https://registry.npmjs.org/$pkg" | jq -r '.repository.url // ""' | sed 's|.*github.com/||;s|\.git$||;s|^git\+https://||')
if [ -n "$REPO" ]; then
SCORE=$(scorecard --repo "github.com/$REPO" --format json 2>/dev/null | jq '.aggregate_score // "N/A"')
echo "$pkg ($REPO): $SCORE"
fi
done
Custom Scorecard with Probes
# Scorecard v5 introduced granular probes
# Run specific probes for more targeted checks
# Check if branch protection requires code review
scorecard --repo github.com/org/repo \
--probes branchProtectionAppliesToAdmins,branchProtectionRequiresCodeOwnerReviews \
--format json | jq '.checks'
# Check CI/CD security probes
scorecard --repo github.com/org/repo \
--probes hasDangerousWorkflowScriptInjection,hasDangerousWorkflowUntrustedCheckout \
--format json
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| Rate limited (403) | GitHub API rate limit exceeded | Use a GitHub App for higher limits (5000/hr vs 60/hr) |
| Check returns -1 | Check not applicable or errored | Review check details for specific error message |
| Branch-Protection score 0 | No branch protection rules | Enable branch protection in GitHub repo settings |
| Vulnerabilities check failing | Known CVEs in dependencies | Update vulnerable dependencies |
| Token-Permissions low score | Overly permissive CI tokens | Use permissions: block in GitHub Actions |
| Pinned-Dependencies low | Using tags instead of hashes | Pin actions/images to SHA hashes |
| SARIF upload failing | Missing security-events: write | Add permission to GitHub Actions workflow |
| Local scan incomplete | Missing git history | Clone with --depth=0 for full history |
# Debug: run with verbose output
scorecard --repo github.com/org/repo --show-details --verbosity debug
# Debug: check specific failing check
scorecard --repo github.com/org/repo --checks Branch-Protection --show-details
# Verify GitHub token scope
curl -s -H "Authorization: Bearer $GITHUB_AUTH_TOKEN" \
https://api.github.com/rate_limit | jq '.rate'
# Check if repo is in the public scorecard database
curl -s "https://api.securityscorecards.dev/projects/github.com/org/repo" | jq '.score'
# Validate SARIF output
cat results.sarif | jq '.runs[0].results | length'