Software Supply Chain Security Assessment: [Product or organisation]
Assessment of how securely software is sourced, built, packaged and
delivered, structured around SLSA specification version 1.2 (Build and
Source tracks, slsa.dev), SBOMs in SPDX 3.0 and CycloneDX 1.7, Sigstore
signing and provenance concepts, the OpenSSF Scorecard checks and VEX
for vulnerability status. It records scope, current and target SLSA
levels, SBOM policy, dependency management, provenance and signing,
Scorecard results, vulnerability management, third-party intake,
CI/CD hardening, findings and a roadmap. Replace every [bracketed]
value and every row marked Example.
Document control
| Field | Value |
|---|
| Document ID | [SCS-PAYAPI-001] |
| Product / scope | [Payments API service and its client SDKs] |
| Build platform assessed | [GitHub Actions, hosted runners; container registry GHCR] |
| Assessment period | YYYY-MM-DD to YYYY-MM-DD |
| Version | [0.1] |
| Status | [Draft / In review / Approved] |
| Assessor | [@security-engineer] |
| Engineering owner | [@platform-lead] |
| SLSA version | 1.2 |
| Classification | [Internal / Confidential] |
| Next assessment | YYYY-MM-DD |
Approvals
| Role | Name | Decision | Date |
|---|
| Assessor | [@name] | [Approved] | YYYY-MM-DD |
| Platform engineering lead | [@name] | [Accepted findings and roadmap] | YYYY-MM-DD |
| Head of security | [@name] | [Accepted residual risk] | YYYY-MM-DD |
Revision history
| Version | Date | Author | Change |
|---|
| 0.1 | YYYY-MM-DD | [@name] | Scope, inventory and build diagram |
| 0.2 | YYYY-MM-DD | [@name] | Example: SLSA gap analysis and Scorecard results |
| 1.0 | YYYY-MM-DD | [@name] | Example: Approved; roadmap to Build L3 agreed |
Contents
1. Introduction and scope
This section states the drivers, scope and method of the assessment.
1.1 Drivers
- Example: Enterprise customers request SBOMs and signed artefacts in contracts from YYYY-MM-DD.
- Example: Regulatory expectations for products with digital elements (for example the EU Cyber Resilience Act) on vulnerability handling and SBOMs.
- [Driver]
1.2 Scope
| In scope | Out of scope |
|---|
Example: 6 repositories: payments-api, payments-worker, sdk-js, sdk-python, infra, shared-actions | Example: Internal tools without production deployment |
| Example: GitHub Actions workflows, GHCR, npm and PyPI publishing | Example: Developer laptops (covered by endpoint policy) |
| [Item] | [Item] |
1.3 Method
The assessment combined [workflow file review, repository settings
export, OpenSSF Scorecard runs, interviews with the platform team and
verification of a sample of published artefacts]. Each SLSA requirement
was assessed as Met, Partial or Not met with evidence.
2. Supply chain overview
The inventory lists every artefact produced; the diagram shows the path
from developer to consumer.
2.1 Artefact inventory
| ID | Artefact | Type | Built by | Published to | Consumers |
|---|
| ART-01 | payments-api image | OCI container | GitHub Actions, hosted runner | GHCR | Production Kubernetes |
| ART-02 | @example/payments-sdk | npm package | GitHub Actions | npm | Customers |
| ART-03 | example-payments | Python wheel | GitHub Actions | PyPI | Customers |
| ART-04 | Helm chart | OCI artefact | GitHub Actions | GHCR | Production |
| [ART-nn] | [Artefact] | [Type] | [Builder] | [Registry] | [Consumers] |
2.2 Source-to-consumer flow
The flow below marks where each control family applies.
2.3 Threats considered
| ID | Threat | Point in flow | Example incident pattern |
|---|
| ST-01 | Unreviewed or malicious source change | Developer to repository | Compromised maintainer account pushes to main |
| ST-02 | Build tampering | Build platform | Malicious step modifies output after tests |
| ST-03 | Compromised dependency | Dependencies | Typosquatted package or hijacked maintainer release |
| ST-04 | Artefact substitution | Registry to consumer | Attacker uploads lookalike image with same tag |
| ST-05 | Secret exfiltration from CI | Build platform | Workflow on pull request from fork reads publishing token |
| [ST-nn] | [Threat] | [Point] | [Pattern] |
3. SLSA assessment
SLSA 1.2 defines two tracks. Levels are cumulative within a track.
3.1 Level summary
| Track | Level | Name on slsa.dev | What it means in practice |
|---|
| Build | L0 | No guarantees | No SLSA requirements met |
| Build | L1 | Provenance exists | Consistent build process; provenance describing how the artefact was built is generated and distributed |
| Build | L2 | Hosted build platform | Build runs on a hosted platform that generates and signs provenance; consumers can check it is authentic |
| Build | L3 | Hardened builds | Platform isolates build runs from each other and keeps signing secrets out of reach of user-defined build steps |
| Source | L1 | Version controlled | Source kept in a modern version control system |
| Source | L2 | History and provenance | Branch history is continuous, immutable and retained; the platform issues provenance for each new revision |
| Source | L3 | Continuous technical controls | Platform enforces the organisation's technical controls on named protected references |
| Source | L4 | Two-party review | Two trusted people review every change to protected branches |
3.2 Current and target levels
| Artefact | Build current | Build target | Source current | Source target | Evidence |
|---|
| ART-01 | Example: L2 | L3 | L3 | L4 | Provenance generated by platform attestation action; branch rulesets on main |
| ART-02 | L1 | L3 | L2 | L4 | Provenance generated by a script inside the build job (not platform-signed) |
| ART-03 | L0 | L2 | L2 | L3 | No provenance published |
| [ART-nn] | [Ln] | [Ln] | [Ln] | [Ln] | [Link] |
3.3 Gap analysis
| Requirement area | Status | Gap | Finding |
|---|
| Provenance generated by the build platform, not by user steps | Partial | ART-02 and ART-03 create provenance in user scripts | SC-002 |
| Provenance signed and verifiable by consumers | Partial | Consumers have no documented verification command | SC-003 |
| Build runs isolated from each other | Met | Hosted ephemeral runners | |
| Signing material inaccessible to build steps | Not met | Publishing token stored as repository secret readable by all jobs | SC-005 |
| Protected branches with enforced controls | Met | Rulesets on main | |
| Two-party review of every change | Partial | Administrators can bypass review | SC-001 |
| [Area] | [Status] | [Gap] | [SC-nnn] |
4. SBOM policy
Software bills of materials are produced for every released artefact
according to the policy below.
| Policy item | Decision |
|---|
| Formats | Example: CycloneDX 1.7 JSON as primary; SPDX 3.0 JSON on customer request |
| Generation point | In the release build, from the lockfile and the final image layers |
| Minimum content | Component name, version, supplier, package URL (purl), hashes, licence, dependency relationships |
| Depth | All transitive dependencies; base image packages for containers |
| Binding to artefact | SBOM attached to the image as a signed attestation referencing the image digest |
| Distribution | Published with each release; available to customers on request through the trust portal |
| Retention | For the support life of the version plus [2 years] |
| Quality check | Automated: every component has a version and purl; fail build if fewer than [95%] do |
| Format | Maintained by | Typical strengths |
|---|
| SPDX 3.0 | Linux Foundation SPDX project (also ISO/IEC 5962 for version 2.2.1) | Licence compliance detail; profiles for security, build and AI |
| CycloneDX 1.7 | OWASP CycloneDX, standardised by Ecma as ECMA-424 | Security use cases; built-in VEX, services and attestations |
5. Dependency management
This section records how third-party code enters and stays in the
product.
| Practice | Current state | Target | Finding |
|---|
| Lockfiles committed for every package manager | Example: Yes (npm, pip-tools) | Yes | |
Install from lockfile only in CI (npm ci, pip install --require-hashes) | Partial: Python installs without hashes | Hash-checked installs | SC-006 |
| Container base images pinned by digest | No: tags such as node:22 | Digest pins updated by bot | SC-007 |
| CI actions pinned by commit SHA | Partial: third-party actions pinned by tag | All by SHA | SC-004 |
| Automated update bot | Yes, weekly, grouped minor updates | Same, plus security updates daily | |
| Private registry or proxy | No | Proxy with allow-list for new packages | SC-008 |
| Unused dependency removal | Ad hoc | Quarterly report | |
| [Practice] | [State] | [Target] | [SC-nnn] |
6. Provenance and signing
Artefacts are signed and carry provenance so that consumers can check
who built them, from which source, on which platform.
6.1 Signing approach
| Item | Decision |
|---|
| Signing model | Example: Keyless signing with Sigstore: short-lived certificate bound to the CI workload identity (OIDC), issued by a certificate authority (Fulcio) |
| Transparency | Signatures recorded in a public transparency log (Rekor) |
| Tooling | [Cosign for containers; npm provenance; PyPI trusted publishing with attestations] |
| Provenance format | SLSA provenance predicate in an in-toto attestation |
| Identity expected by verifiers | https://github.com/[org]/[repo]/.github/workflows/release.yml@refs/tags/v* |
6.2 Verification points
| Where | What is verified | Enforcement | Status |
|---|
| Kubernetes admission | Image signature and provenance from the expected workflow identity | Policy controller blocks unsigned images | Example: Audit mode only |
| Customer documentation | Command to verify image and package signatures | Published guide | Missing (SC-003) |
| Internal consumers of SDKs | npm provenance check | npm audit signatures in CI | [Status] |
7. OpenSSF Scorecard results
Scorecard results for [repository] on YYYY-MM-DD (aggregate score
[6.8]/10).
| Check | Score | Notes | Finding |
|---|
| Binary-Artifacts | 10 | No binaries in repository | |
| Branch-Protection | 8 | Admins can bypass | SC-001 |
| CI-Tests | 10 | Tests run on all PRs | |
| CII-Best-Practices | 0 | No OpenSSF Best Practices badge | [Accept] |
| Code-Review | 9 | 2 unreviewed commits in sample | SC-001 |
| Contributors | [n/a] | Internal project | |
| Dangerous-Workflow | 10 | No untrusted checkout in privileged triggers | |
| Dependency-Update-Tool | 10 | Update bot configured | |
| Fuzzing | 0 | No fuzzing of parsers | SC-009 |
| License | 10 | Licence file present | |
| Maintained | 10 | Active | |
| Packaging | 10 | Publishing workflow detected | |
| Pinned-Dependencies | 4 | Actions and base images not pinned | SC-004, SC-007 |
| SAST | 7 | CodeQL on default branch only | |
| SBOM | 0 | SBOM not published with releases | SC-010 |
| Security-Policy | 10 | SECURITY.md present | |
| Signed-Releases | 3 | Some releases unsigned | SC-002 |
| Token-Permissions | 5 | Default workflow token has write access | SC-005 |
| Vulnerabilities | 8 | 2 open advisories in dependencies | |
| Webhooks | [n/a] | Not evaluated | |
8. Vulnerability management and VEX
This section covers detection, triage, remediation targets and
vulnerability exploitability exchange (VEX) statements.
8.1 Process
| Step | Practice |
|---|
| Detection | Example: SBOM-based scanning daily against OSV and the GitHub Advisory Database |
| Triage | Within 2 business days: reachable? exploitable in our configuration? |
| Prioritisation | Severity adjusted by exploit availability (for example CISA KEV listing) and exposure |
| Remediation targets | Critical 7 days, High 30 days, Medium 90 days |
| Communication | VEX document published with each release and on change of status |
8.2 VEX statements
Each statement uses one of the standard statuses: not affected, affected,
fixed or under investigation. "Not affected" requires a justification.
| Vulnerability | Component | Product version | Status | Justification or action | Published |
|---|
| Example: CVE-YYYY-NNNNN | xml-parser 2.3.1 | payments-api 4.2.0 | Not affected | Vulnerable code not present in the build (feature compiled out) | YYYY-MM-DD |
| CVE-YYYY-NNNNN | http-client 1.8.0 | payments-api 4.2.0 | Fixed | Upgraded to 1.8.2 in 4.2.1 | YYYY-MM-DD |
| [ID] | [Component] | [Version] | [Status] | [Justification] | YYYY-MM-DD |
| VEX format | Notes |
|---|
| CycloneDX VEX | Embedded in or alongside the CycloneDX BOM |
| CSAF VEX profile | OASIS Common Security Advisory Framework |
| OpenVEX | Minimal JSON format from the OpenSSF community |
9. Third-party and open source intake
New third-party components pass the intake checks below before first use.
| Check | Criterion | Who |
|---|
| Need | No existing approved component covers the use | Requesting engineer |
| Health | Example: Scorecard at least 5; release in the last 12 months; more than one maintainer | Reviewer |
| Licence | Compatible with product licence policy | Licence tool, legal on exceptions |
| Security history | No unpatched critical advisories; responsive to past reports | Reviewer |
| Name check | Not a lookalike of a popular package; publisher verified | Automated check |
| Install scripts | No install-time scripts, or reviewed if present | Reviewer |
| Approval record | Ticket with decision and review date | [@security-champion] |
10. CI/CD hardening
| Control | Current | Target | Finding |
|---|
| Default workflow token permissions read-only; elevate per job | Example: Write by default | Read-only default | SC-005 |
| Publishing via OIDC trusted publishing, no long-lived tokens | Long-lived npm token | OIDC | SC-005 |
| Workflows triggered by forks have no secrets and no write token | Met | Met | |
| Protected environments with required reviewers for release | Partial | Required for production and package publishing | SC-011 |
| Self-hosted runners ephemeral and isolated | n/a (hosted only) | n/a | |
| Changes to workflow files need code owner review | Not met | CODEOWNERS on .github/ | SC-001 |
| Audit log of CI configuration changes retained | 90 days | 1 year | |
| [Control] | [Current] | [Target] | [SC-nnn] |
11. Findings
| ID | Title | Area | Severity | Evidence | Recommendation | Owner | Status |
|---|
| SC-001 | Administrators can bypass review on main | Source | High | Ruleset bypass list includes org admins | Remove bypass; break-glass procedure with alert | [@name] | [Open] |
| SC-002 | Provenance not platform-generated for SDKs | Build | Medium | Provenance created by script in build job | Use platform attestation / trusted publishing | [@name] | [Open] |
| SC-003 | No consumer verification guide | Provenance | Medium | Docs lack verification steps | Publish verification commands | [@name] | [Open] |
| SC-004 | Third-party actions pinned by tag | Dependencies | High | 14 of 22 actions pinned by mutable tag | Pin by commit SHA; update bot | [@name] | [Open] |
| SC-005 | Long-lived publishing token readable by all jobs | CI/CD | Critical | npm token in repository secrets | OIDC trusted publishing; scoped environment | [@name] | [In progress] |
| SC-010 | No SBOM published | SBOM | Medium | Releases lack SBOM | Generate CycloneDX in release job | [@name] | [Open] |
| [SC-nnn] | [Title] | [Area] | [Severity] | [Evidence] | [Recommendation] | [@name] | [Status] |
12. Roadmap
The roadmap moves all in-scope artefacts to Build L3 and Source L3 within
[two quarters].
| Milestone | Outcome | Target date | Owner |
|---|
| M1 | No long-lived publishing secrets; all actions pinned | YYYY-MM-DD | [@name] |
| M2 | All artefacts at Build L3 with consumer verification guide | YYYY-MM-DD | [@name] |
| M3 | SBOM and VEX published with every release | YYYY-MM-DD | [@name] |
| [Mn] | [Outcome] | YYYY-MM-DD | [@name] |
13. Appendices
The appendices hold the glossary and references.
13.1 Glossary
| Term | Meaning |
|---|
| SLSA | Supply-chain Levels for Software Artifacts, an OpenSSF specification |
| Provenance | Verifiable record of how, where and from what an artefact was built |
| SBOM | Software bill of materials: list of components in an artefact |
| VEX | Vulnerability exploitability exchange: statement of whether a product is affected by a vulnerability |
| purl | Package URL, a standard identifier for packages |
| Attestation | Signed statement about an artefact, such as provenance or an SBOM |
13.2 References
| Reference | Use |
|---|
| SLSA specification v1.2, slsa.dev | Tracks and levels in section 3 |
| SPDX specification 3.0, spdx.dev | SBOM format |
| CycloneDX specification 1.7, cyclonedx.org | SBOM and VEX format |
| Sigstore project documentation, sigstore.dev | Signing model in section 6 |
| OpenSSF Scorecard, github.com/ossf/scorecard | Checks in section 7 |
| [Internal secure development policy] | Remediation targets |
Standard and licence note
Based on the SLSA specification version 1.2 (slsa.dev, published by the
OpenSSF under the Community Specification License 1.0) for the Build
track levels L0 to L3 and Source track levels L1 to L4, together with the
SPDX 3.0 and CycloneDX 1.7 SBOM specifications, Sigstore signing
concepts, the OpenSSF Scorecard check names (Apache License 2.0) and
common practice for VEX. Level names are given as published; all
descriptions and requirements summaries are original paraphrases and no
specification text is reproduced. Consult each specification for its
normative requirements. Template licence: MIT.