# 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*.

<!--
Guidance: How to use this template
- Assess one product or one build platform per document. An organisation
  with many repositories can sample the top ten by risk and record the
  sample in section 1.
- Start with the artefact inventory and build diagram (section 2); every
  later section refers to those IDs.
- Record evidence for every "met" status: a link to a workflow file, a
  provenance attestation, a Scorecard run. Claims without evidence are
  findings.
- SLSA levels are earned per artefact and per track, not per company.
  State the level of each artefact separately.
- Re-run the assessment yearly and after any change to the build platform.
-->

## Document control

<!-- Guidance: Identify the assessment, the product and build platform versions assessed, and who owns the results. -->

| 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

<!-- Guidance: Record changes in levels, findings and roadmap, not wording. -->

| 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

<!-- Guidance: Keep aligned with the headings below. -->

1. [Introduction and scope](#1-introduction-and-scope)
2. [Supply chain overview](#2-supply-chain-overview)
3. [SLSA assessment](#3-slsa-assessment)
4. [SBOM policy](#4-sbom-policy)
5. [Dependency management](#5-dependency-management)
6. [Provenance and signing](#6-provenance-and-signing)
7. [OpenSSF Scorecard results](#7-openssf-scorecard-results)
8. [Vulnerability management and VEX](#8-vulnerability-management-and-vex)
9. [Third-party and open source intake](#9-third-party-and-open-source-intake)
10. [CI/CD hardening](#10-cicd-hardening)
11. [Findings](#11-findings)
12. [Roadmap](#12-roadmap)
13. [Appendices](#13-appendices)

## 1. Introduction and scope

<!-- Guidance: Say why the assessment is happening (customer requirement, regulation, incident, internal policy) and exactly which repositories, artefacts and platforms are covered. -->

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

<!-- Guidance: Inventory what is produced and draw the path from source to consumer. Threats sit at each arrow: source tampering, build tampering, dependency compromise, distribution tampering. -->

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.

```mermaid
flowchart LR
  Dev["Developer"] -->|"signed commits, PR review"| Repo["Source repository"]
  Deps["Third-party dependencies"] -->|"lockfile, intake review"| Build
  Repo -->|"trigger"| Build["Hosted build platform"]
  Build -->|"provenance + signature"| Reg["Registry"]
  Build -->|"SBOM"| Reg
  Reg -->|"verify signature and provenance"| Deploy["Deployment admission"]
  Reg -->|"download"| Cust["Customers"]
```

### 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

<!-- Guidance: SLSA 1.2 has a Build track (levels L0 to L3) and a Source track (levels L1 to L4). Assess current and target level per artefact. Use the requirement pages on slsa.dev as the checklist; the summaries here are paraphrases. -->

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

<!-- Guidance: Decide format, generation point, content depth, distribution and retention. Generate the SBOM in the build from the resolved dependency graph, not from a later scan of the image only. -->

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

<!-- Guidance: Describe how dependencies are declared, pinned, updated and removed. Pinning without an update process only freezes old vulnerabilities. -->

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

<!-- Guidance: Describe what is signed, with which keys or identities, where signatures and attestations are stored, and how consumers and deployment verify them. Signing without verification gives no protection. -->

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

<!-- Guidance: Run Scorecard on each in-scope repository and record scores per check (0 to 10). Treat low scores as prompts for investigation, not automatic findings; some checks do not apply to private or monorepo setups. -->

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

<!-- Guidance: Describe how vulnerabilities in dependencies are detected, triaged and communicated, including how "not affected" decisions are published as VEX so customers do not chase false positives. -->

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

<!-- Guidance: Define what happens before a new dependency, action or base image is first used. Most supply chain compromises enter through a new, lightly reviewed component. -->

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

<!-- Guidance: The build platform is the most privileged system in the chain. Review permissions, secrets, triggers and runners. -->

| 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

<!-- Guidance: One row per finding with severity, evidence and recommendation. Severity reflects the chance of a real compromise and its blast radius, not the Scorecard number. -->

| 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

<!-- Guidance: Sequence work so the riskiest gaps close first, and tie milestones to SLSA levels so progress is measurable. -->

The roadmap moves all in-scope artefacts to Build L3 and Source L3 within
[two quarters].

```mermaid
gantt
  title Supply chain security roadmap
  dateFormat YYYY-MM-DD
  section Critical
  SC-005 OIDC publishing :a1, 2026-11-02, 10d
  SC-004 pin actions by SHA :a2, 2026-11-02, 5d
  section Build L3
  Platform provenance for SDKs :a3, 2026-11-16, 15d
  Admission policy enforce mode :a4, 2026-12-01, 15d
  section SBOM and VEX
  CycloneDX in release job :a5, 2026-11-16, 10d
  VEX publication :a6, 2026-12-01, 10d
```

| 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

<!-- Guidance: Glossary and references so the document stands on its own. -->

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.
