
In March 2024, XZ Utils, a compression utility present on nearly every Linux server, was compromised by a backdoor hidden over two years. The attacker had earned the maintainer's trust, obtained commit rights, then injected malicious code allowing remote code execution through SSH. That attack captures the software supply chain dilemma perfectly: how do you trust dependencies maintained by strangers?
Supply chain attacks are exploding. According to Sonatype, they rose by 245%
in three years. SolarWinds, Event-Stream, Polyfill.io, tj-actions: every
incident shows that the popularity of a project does not guarantee its
security. An npm package with millions of downloads can be taken over by an
attacker. A GitHub action with thousands of stars can exfiltrate your secrets.
The fundamental problem: we trust blindly. We install hundreds of
dependencies without checking who maintains them, how they are built, whether
the releases are signed. We use GitHub actions with mutable tags (@v1) that
can change at any moment. We load scripts from third-party CDNs with no control.
OpenSSF Scorecard gives an objective answer to that question of trust. This tool, built by the Open Source Security Foundation, analyses a GitHub repository automatically and gives it a score from 0 to 10 based on concrete security criteria: branch protection, code reviews, signatures, known vulnerabilities, dangerous patterns in the workflows, and more.
What you will learn
- Understand what Scorecard evaluates and how to read the results
- Install and use the CLI against a public repository
- Wire Scorecard into a CI/CD pipeline, on GitHub and on GitLab
- Read the 19 checks and know the remediation for each score
- Raise your score through a progressive action plan
What is OpenSSF Scorecard?
Scorecard is an automated tool measuring the security posture of an open source project. It runs a series of checks (heuristic controls) and produces a score for each of them.
The idea is simple: rather than trusting a dependency blindly, you objectively verify whether the project follows security good practices.
Why it is useful
- Assessing a dependency before adoption: a score below 5 should raise a flag
- Auditing your own projects: identifying the weaknesses to fix
- Proving your security maturity: showing a score badge in your README
- Automating the monitoring: wiring Scorecard into the CI/CD
What Scorecard evaluates
Scorecard analyses varied aspects of a project's security:
| Category | Example checks |
|---|---|
| Code protection | Branch Protection, Code Review, Signed Releases |
| Build quality | Pinned Dependencies, CI Tests, Fuzzing |
| Maintenance | Active maintainers, response to vulnerabilities |
| Operational security | Dangerous Workflows, Token Permissions |
Every check returns a score from 0 to 10 with a reason explaining the result.
Installation
Scorecard can be installed in several ways depending on the environment.
# Get the latest available versionVERSION=$(curl -s https://api.github.com/repos/ossf/scorecard/releases/latest | grep tag_name | cut -d '"' -f 4)
# Download the releasewget "https://github.com/ossf/scorecard/releases/download/${VERSION}/scorecard_${VERSION#v}_linux_amd64.tar.gz"
# Extract and installtar xzf scorecard_*_linux_amd64.tar.gzsudo install scorecard /usr/local/bin/scorecard
# Check the installationscorecard version# Installation through Homebrewbrew install scorecard
# Check the installationscorecard version# Use the official image, pinned by digestdocker run -it \ gcr.io/openssf/scorecard:v5.5.0@sha256:b9a535801cb5fc8e7b2bea4cf45dd2db9a342cab8cc32bb5be2ac1355a95356f \ --repo=github.com/org/projectBasic usage
Configuring GitHub authentication
A GitHub token is required
Without a GitHub token, Scorecard hits the API limits very quickly (60 requests per hour). In practice, a token is indispensable to analyse a project.
Token type and permissions:
| Token type | Required scope | Limitation |
|---|---|---|
| Classic token | public_repo (or repo for private repositories) | Full access to every check |
| Fine-grained token | Contents: read, Metadata: read | Cannot read the classic branch protection rules |
Recommendation
To obtain the Branch-Protection score, use a classic token with the
public_repo scope. Fine-grained tokens produce an error on that check because
they have no access to GitHub's classic protection rules. See the
official documentation.
# Create a classic token at https://github.com/settings/tokens# Minimal scope: public_repo (or repo for private repositories)
# Export the tokenexport GITHUB_AUTH_TOKEN=ghp_xxxxxxxxxxxxAnalysing a GitHub project
Once the token is configured, the basic command analyses a repository:
# Analyse a public projectscorecard --repo=github.com/kubernetes/kubernetesReading the output
Scorecard prints a summary per check. Here is a real example on the Kubernetes project:
Aggregate score: 6.8 / 10
Check scores:|---------|------------------------|-----------------------------------------------------------------------|| SCORE | NAME | REASON ||---------|------------------------|-----------------------------------------------------------------------|| 10 / 10 | Binary-Artifacts | no binaries found in the repo || 10 / 10 | CI-Tests | 13 out of 13 merged PRs checked by a CI test || 5 / 10 | CII-Best-Practices | badge detected: Passing || 8 / 10 | Code-Review | Found 13/16 approved changesets || 10 / 10 | Contributors | project has 37 contributing companies or organizations || 0 / 10 | Dependency-Update-Tool | no update tool detected || 10 / 10 | Fuzzing | project is fuzzed || 10 / 10 | License | license file detected || 10 / 10 | Maintained | 30 commit(s) and 4 issue activity found in the last 90 days || 0 / 10 | Pinned-Dependencies | dependency not pinned by hash detected || 0 / 10 | SAST | SAST tool is not run on all commits || 10 / 10 | Security-Policy | security policy file detected || 8 / 10 | Vulnerabilities | 2 existing vulnerabilities detected ||---------|------------------------|-----------------------------------------------------------------------|Checks showing "?"
Some checks can show ? instead of a score. That means the check could not run
(insufficient data, token permissions, or a feature the project does not use).
Output formats
Scorecard supports several formats for integration with other tools:
# JSON format for automated processingscorecard --repo=github.com/org/project --format=json > scorecard.json
# SARIF format for GitHub Securityscorecard --repo=github.com/org/project --format=sarif > scorecard.sarifThe checks in detail
Scorecard runs 19 checks spread across several categories. Each check evaluates one specific security aspect and gives a score from 0 to 10. Here is the full list with the evaluation criteria and the actions that raise each score.
Critical checks (high risk)
Binary-Artifacts
Risk: unauditable code in the repository.
Checks the absence of executable binary files (.exe, .class, .pyc,
minified JS, and so on) in the source code. Binaries cannot be reviewed and may
carry malicious or obsolete code.
Score 10/10: no binary found in the repository.
Remediation: remove the binaries and generate them from the source code at build time.
Branch-Protection
Risk: malicious code injected with no control.
Checks that the main branches (main, master) are protected through the
GitHub protection rules.
The tiered scale:
| Points | Requirements |
|---|---|
| 3/10 | Force push and branch deletion forbidden |
| 6/10 | + At least 1 reviewer required, pull request mandatory before merge |
| 8/10 | + At least 1 required CI status check |
| 9/10 | + At least 2 reviewers, review by code owners |
| 10/10 | + Approvals dismissed after a new commit, admins included |
Remediation: configure the protection rules under Settings > Branches > Branch protection rules on GitHub.
Code-Review
Risk: vulnerabilities or malicious code going undetected.
Measures whether changes pass through human review before integration. It analyses the last 30 commits to check they were approved.
The scale:
- -7 points if a human change is not reviewed
- -3 additional points if several changes are not reviewed
- -3 points if bot changes are not reviewed
AI reviews
Reviews by bots (including AI/ML ones) do not count as code review, because they do not guarantee that a second person understood the change.
Remediation: make reviews mandatory through the branch protection rules.
Dangerous-Workflow
Risk: repository compromise (critical).
Detects dangerous patterns in GitHub Actions workflows:
- Untrusted checkout:
pull_request_targetorworkflow_runwith an explicit checkout of the pull request, which lets the pull request author run arbitrary code with the repository secrets - Script injection: unsanitised GitHub context variables in inline scripts
(for example
${{ github.event.issue.title }})
Score 10/10: no dangerous pattern detected.
Remediation: read the GitHub Security Lab guide and the Securing pull_request_target guide.
Signed-Releases
Risk: installing malicious releases.
Checks that releases are signed cryptographically. It analyses the last 5 releases for the presence of signature files.
Extensions looked for: .minisig, .asc (PGP), .sig, .sign,
.sigstore, .sigstore.json, .intoto.jsonl (SLSA).
The scale:
- 8/10: a signature present for every release
- 10/10: a SLSA attestation (
.intoto.jsonl) present
Remediation: sign your releases and publish provenance attestations; see GitHub Actions attestations.
Token-Permissions
Risk: tokens holding excessive permissions.
Checks that GitHub Actions workflows follow the principle of least privilege for
the GITHUB_TOKEN.
The optimal score: permissions set to read-only at the global level, and write permissions declared only on the jobs that need them.
# ✅ Good practicepermissions: contents: read # Read-only by default
jobs: deploy: permissions: contents: write # Write for this job onlyRemediation: use StepSecurity to work out the minimal permissions needed, and see GITHUB_TOKEN permissions.
Vulnerabilities
Risk: known, exploitable vulnerabilities.
Checks through OSV (Open Source Vulnerabilities) whether the project or its dependencies carry open, unfixed vulnerabilities.
The score: depends on the number and the severity of the vulnerabilities detected.
Remediation: fix the vulnerabilities in the code or update the dependencies to non-vulnerable versions.
Build quality checks
CI-Tests
Risk: bugs and vulnerabilities going undetected.
Checks whether the project runs automated tests before merging pull requests. It analyses the last 30 commits for the presence of CI checks.
Systems detected: GitHub Actions, Travis CI, CircleCI, Jenkins, AppVeyor, BuildKite, Woodpecker, and any system whose name contains "test" or "e2e".
Score 10/10: every recent commit went through CI tests.
Remediation: add tests with GitHub Actions or another CI system.
Dependency-Update-Tool
Risk: outdated dependencies carrying known vulnerabilities.
Checks whether the project uses an automatic dependency update tool.
Tools detected:
- Dependabot
- Renovate
- PyUp (Python)
Score 10/10: a configuration file for one of those tools is detected.
Remediation: enable Dependabot in the GitHub settings or configure Renovate at the root of the project.
Fuzzing
Risk: undiscovered vulnerabilities in the code.
Checks whether the project uses fuzzing (testing with random data) to find bugs.
Methods detected:
- Inclusion in OSS-Fuzz
- ClusterFuzzLite in the repository
- Native Go fuzz tests (
func FuzzXxx) - Property-based testing libraries (QuickCheck, fast-check, FsCheck, and so on)
Remediation: add the project to OSS-Fuzz or use the language's native fuzzing.
Pinned-Dependencies
Risk: compromised dependencies (a supply chain attack).
Checks that dependencies are pinned to hashes rather than to mutable versions or tags.
What is analysed:
- GitHub actions (they must use a SHA, not
@v1) - Docker images (they must use a digest)
- Dependencies in shell scripts and Dockerfiles
# ❌ A mutable tag: it can change without notice- uses: actions/checkout@v4
# ✅ A pinned SHA: immutable- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11Remediation: use StepSecurity
to pin the actions automatically, and Renovate with pinDigests: true for the
Docker images. The procedure is detailed in
Pinning actions by SHA.
SAST
Risk: bugs and vulnerabilities in the source code.
Checks whether the project runs static application security testing (SAST) on pull requests.
Tools detected:
- CodeQL (github-code-scanning)
- SonarCloud
- The
github/codeql-actionaction in the workflows
Remediation: enable CodeQL under Settings > Security > Code scanning or
add the github/codeql-action action to a workflow.
Governance checks
CII-Best-Practices
Risk: security good practices not followed.
Checks whether the project earned an OpenSSF Best Practices badge.
The scale:
- 2/10: badge in progress
- 5/10: "Passing" badge
- 7/10: "Silver" badge
- 10/10: "Gold" badge
Remediation: register on bestpractices.dev and fill in the questionnaire.
Contributors
Risk: a project depending on a single organisation.
Checks whether the project has contributors from several different organisations (based on the "Company" field of the GitHub profiles).
Score 10/10: at least 3 different organisations among the last 30 commits, with at least 5 commits each.
Remediation: encourage contributors to fill in their organisation in their GitHub profile.
License
Risk: an obstacle to security auditing, and a legal risk.
Checks for the presence of a licence in the repository.
The scale:
- 6/10: a
LICENSE,COPYINGorCOPYRIGHTfile detected - 9/10: + the file at the root of the project
- 10/10: + a licence recognised by the FSF or OSI (an SPDX identifier)
Remediation: add a LICENSE file at the root with an
SPDX licence.
Maintained
Risk: unfixed vulnerabilities in an abandoned project.
Evaluates the recent activity of the project over the last 90 days.
Score 10/10: at least 1 commit per week over the last 90 days.
Partial score: issue activity from collaborators or maintainers.
Score 0: an archived project.
Careful
An inactive project can be the target of a maintainer takeover, an attacker regaining control to inject malicious code (see XZ Utils).
Security-Policy
Risk: insecure reporting of vulnerabilities.
Checks for the presence of a SECURITY.md file explaining how to report
vulnerabilities responsibly.
The scale:
- 6/10: a contact email or URL present
- 9/10: + explanatory text beyond the bare links
- 10/10: + disclosure timelines mentioned (for example "90 days")
Remediation: create a SECURITY.md file at the root with the reporting
instructions. On GitHub, use Settings > Security > Security advisories.
Other checks
Packaging
Checks whether the project publishes packages through GitHub Packages or publication actions towards npm, PyPI and others.
SBOM
Checks for the presence of an SBOM in the source code or in the release artefacts.
Webhooks
Checks that the configured webhooks use a secret to authenticate the requests.
CI/CD integration
GitHub Actions
The native integration runs Scorecard automatically and publishes the results in the GitHub Security tab:
name: Scorecard Analysis
on: push: branches: [ "main" ] schedule: # Weekly analysis on Sunday at midnight - cron: '0 0 * * 0'
permissions: # Needed to publish the results security-events: write id-token: write
jobs: analysis: name: Scorecard analysis runs-on: ubuntu-24.04
steps: - name: Checkout code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false
- name: Run analysis uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4 with: results_file: results.sarif results_format: sarif publish_results: true
- name: Upload to code-scanning uses: github/codeql-action/upload-sarif@17573ee1cc1b9d061760f3a006fc4c4f1698e080 with: sarif_file: results.sarifPublishing the results
The publish_results: true option shows the score on
securityscorecards.dev and gives you a badge
for the README.
GitLab CI
On GitLab, you use the CLI directly:
scorecard: stage: security image: gcr.io/openssf/scorecard:v5.5.0@sha256:b9a535801cb5fc8e7b2bea4cf45dd2db9a342cab8cc32bb5be2ac1355a95356f variables: GITHUB_AUTH_TOKEN: $GITLAB_TOKEN script: - scorecard --repo=gitlab.com/$CI_PROJECT_PATH --format=json > scorecard.json artifacts: reports: codequality: scorecard.json paths: - scorecard.json rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCHShowing the score badge
Once the results are published, you can add a badge to the README to show the hardening effort:
The badge updates automatically after each analysis.
Raising your score
Here is a progressive action plan to raise a project's score:
-
Enable branch protection
In the GitHub settings, configure:
- Mandatory review by at least 1 person
- Required CI statuses before merge
- Force push forbidden
-
Pin the dependencies
Replace every mutable tag with a SHA in the GitHub Actions workflows and the Dockerfiles.
-
Sign the releases
Sign the artefacts and publish provenance attestations.
-
Enable Dependabot or Renovate
Configure automatic dependency updates to receive the security fixes.
-
Audit the workflows
Check there is no dangerous pattern and minimise the token permissions.
Scorecard in a DevSecOps strategy
Scorecard fits naturally into a wider supply chain security approach. It checks the development practices upstream, while the scanners detect the vulnerabilities in the artefacts produced. The combination gives you defence in depth: a repository can hold no known CVE and still be one stolen maintainer account away from compromise, which is exactly what Scorecard measures and a scanner does not.
Key points
- Scorecard gives an objective answer to the question of trusting an open source project, in seconds.
- Analyse your critical dependencies before adoption: a score below 5 should raise a flag.
- Wire Scorecard into your CI/CD to watch your own projects over time, with a weekly schedule.
- The three checks that move the needle fastest are Branch-Protection, Pinned-Dependencies and Token-Permissions.
- Show the badge to make the security effort visible, and combine Scorecard with artefact scanners for defence in depth.
- A good Scorecard score does not guarantee the absence of vulnerabilities, but it significantly cuts the risk of a maintainer takeover and of supply chain attacks like the XZ Utils one.
Next steps
- Pinning actions by SHA: the fix for the Pinned-Dependencies check, the most frequently failed one.
- GITHUB_TOKEN permissions: what the Token-Permissions check expects, job by job.
- Security checklist: the recap that turns the score into concrete actions on your workflows.
Resources
- OpenSSF Scorecard, the official documentation
- GitHub ossf/scorecard
- The Scorecard GitHub Action
- Scorecard Monitor, multi-project tracking
- Open Source Malware, a community database of malicious packages (npm, PyPI, NuGet)