---
namespace: aiwg
name: supply-chain-trust
platforms: [all]
description: Decision-aid skill for supply-chain trust beyond CVE scanning and SBOM. Covers dependency pinning depth, reproducible builds, snapshot pinning, firmware version locking, and vendor+hash-lock for critical-path deps

---

# supply-chain-trust

Decision aid for verifying that the code you ship is the code you think you're shipping. Use when designing or reviewing systems whose threat model includes supply-chain compromise (build host, dependency mirror, package registry, firmware) — which is most production systems in 2026.

The skill is distinct from `sdlc-complete`'s SBOM and CVE-scanning capabilities. SBOM tells you **what is there**. CVE scanning tells you **what is known-broken**. This skill answers **"can I prove that what I shipped is what I expected, end-to-end"** — which neither of the others does.

## Triggers

- "reproducible build"
- "snapshot pinning" / "snapshot.debian.org"
- "vendor wheels" / "hash-locked deps"
- "firmware version" / "firmware pinning"
- "in-toto" / "SLSA"
- "transparency log" / "Sigstore"
- "build host compromise"
- "supply chain attack"

## When NOT to use this skill

- Pure CVE scanning of declared dependencies (use `sdlc-complete/skills/security-audit`)
- SBOM generation (use existing SBOM tooling — CycloneDX, SPDX)
- License compliance (out of scope; use a license scanner)

---

## Section 1: The four layers of supply-chain trust

```
Layer 4: Hardware / firmware
            ↑ (does the chip do what it says?)
Layer 3: Build environment
            ↑ (was the binary produced from the source we think?)
Layer 2: Source dependencies
            ↑ (did we get the source we expected?)
Layer 1: Source we wrote
            ↑ (we can audit this)
```

Each layer has its own attack surface and its own mitigations:

| Layer | Attack | Mitigation |
|---|---|---|
| 1 (own source) | malicious commit by insider | code review, signed commits, branch protection |
| 2 (deps) | typosquat, compromised maintainer, malicious update | pinning + hash-lock + vendoring; transparency logs |
| 3 (build) | compromised CI, build host malware | reproducible builds, signed-and-attested artifacts (in-toto, SLSA) |
| 4 (hardware) | malicious firmware, supply-chain implant | measured boot, vendor diversity, audit |

A system is only as trustworthy as the weakest layer in the chain it actually depends on.

---

## Section 2: Dependency pinning — beyond `requirements.txt`

### Suggested default: full hash-locked dependency manifests

For each language ecosystem:

| Ecosystem | Default tool | What it produces |
|---|---|---|
| Python | `pip-tools` (`pip-compile --generate-hashes`) → `requirements.txt` with hashes | `package==1.2.3 --hash=sha256:abc...` per dep, including transitive |
| Node | `npm ci` against `package-lock.json` (with `integrity` field), or `pnpm` | per-package SHA-512 integrity |
| Rust | `cargo` lock file (`Cargo.lock`) — versions only; for hashes use `cargo vet` |
| Go | `go.mod` + `go.sum` (per-module SHA-256) |
| Ruby | `Bundler` lockfile + `bundle config set --local frozen true` |
| Maven/Gradle | `dependency:resolve-plugin` with checksum verification |

**Required**: every dependency, including transitive, must have a hash in your lockfile. If a tool can't produce hashed locks, vendor the dep.

### Vendoring critical-path deps

For dependencies in security-sensitive paths (auth, crypto, key handling), go further than hash-locking — **vendor** them:

```
your-repo/
  vendor/
    python-fido2-1.1.3/        # checked-in source of the dep
    cryptography-41.0.7/        # ditto
    ...
  Cargo.toml or pyproject.toml  # references vendor/ paths, not registry
```

Why vendoring on top of hash-locking:

- Hash-locking verifies you got the bytes you expected; vendoring lets you AUDIT those bytes
- A compromised registry could publish a new "version" with a malicious patch; you control what's in `vendor/`
- Reduces transitive surface — you can prune deps that you don't actually use

Cost: you own update cadence. Acceptable for security-critical paths; impractical for everything.

### Anti-pattern: SHA-verified `.deb` whose SHA came from poisoned `apt` repo (review M10)

Original: bootstrap verifies SHA-256 of each downloaded `.deb`, but the SHA-256 manifest itself comes from `apt-cache` against the build-time `apt` repo.

What this skill flags: the verification is **circular within the same trust domain**. If `apt` is compromised, the manifest is compromised, the SHAs are compromised, all three layers verify a poisoned package.

Remediation:

- **Pin to `snapshot.debian.org`** URLs with a specific timestamp (`http://snapshot.debian.org/archive/debian/20260301T000000Z/`) — content-addressed, immutable
- **Verify signed Debian `Release` file** with explicit Debian archive signing keys, ground-truth at the timestamp
- **Pin transitive `.deb` URLs** discovered at that timestamp; commit the resulting SHA manifest to your **signed** git repo

The hash of the package must come from a **separately-trusted channel** than the package itself.

---

## Section 3: Reproducible builds

### What it gives you

A reproducible build means: given the same source, the same build environment, and the same build inputs, **any builder produces a byte-for-byte identical output**. This lets you:

- Verify a third-party-built binary against your own rebuild
- Detect compromised CI by comparing CI output to your local rebuild
- Allow others to verify your published artifacts by rebuilding from source

### Suggested defaults

| Use case | Approach |
|---|---|
| Bootstrap installers | NixOS — reproducible by construction; the entire system specification is hash-tracked |
| Container images | Bazel + `rules_oci` OR Nix-built OCI images; pinned base layer with verified digest |
| Linux distro packaging | Reproducible Builds project tooling (`reproducible-builds.org`); `dpkg --reproducible` flag in Debian |
| Cross-platform binaries | Static linking, hermetic build env (Bazel), check `diffoscope` between rebuilds |

### Verification step

```bash
# Local rebuild
bazel build //my:artifact
sha256sum bazel-bin/my/artifact

# Compare to CI-published
sha256sum downloaded/artifact.tar.gz

# If they differ, run diffoscope to see what diverges
diffoscope bazel-bin/my/artifact downloaded/artifact.tar.gz
```

Common reproducibility breakers: timestamps in archives, build-time UUIDs, parallel-build nondeterminism, locale-dependent string sorting. The `reproducible-builds.org` site catalogs known issues per ecosystem.

### When reproducibility isn't worth it

For internal tools with a single source-of-truth build host and signed output, the value is marginal. Reproducibility shines when:

- You publish artifacts users will run (binaries, container images)
- Your CI runs untrusted code (third-party PRs, etc.)
- Your build host might be compromised and you want a way to detect it

---

## Section 4: Build attestation (in-toto, SLSA)

### Suggested default: SLSA Level 3+ attestation for production releases

SLSA (Supply-chain Levels for Software Artifacts) defines compliance levels:

| Level | What it requires | What it tells consumers |
|---|---|---|
| 0 | nothing | "this came from somewhere" |
| 1 | build process documented | "the build is repeatable in principle" |
| 2 | build runs on hosted CI; provenance generated | "we know which CI built it" |
| 3 | build is hermetic, isolated; provenance is signed and tamper-evident | "we can prove the build chain end-to-end" |
| 4 | additional constraints — two-person review, hermetic builds | "highest assurance" |

**Tooling:**

- `cosign` (Sigstore) — signs container images and arbitrary blobs; integrates with Rekor transparency log
- `slsa-github-generator` — produces SLSA L3 provenance from GitHub Actions
- `in-toto` (CMU) — generic supply-chain attestation framework
- `Tekton Chains` — Kubernetes-native build attestation

### Verification on consumer side

```bash
cosign verify --certificate-identity-regexp=...@my-org \
    --certificate-oidc-issuer=https://token.actions.githubusercontent.com \
    ghcr.io/my-org/my-image:1.2.3
```

Pin **specific certificate identities and OIDC issuers**. A bare `cosign verify` can be satisfied by any signature.

---

## Section 5: Hardware / firmware version locking

### Required pattern (review L6)

For systems with hardware-backed cryptographic operations (HSMs, YubiKeys, TPM-equipped hosts), pin to a known-good firmware range. Different firmware versions can have:

- Different cryptographic primitive support (FIDO2 features, attestation behavior)
- Different timing characteristics (side-channel surface)
- Different bug profiles

Example: YubiKey 5 firmware 5.4 vs 5.7 have **different FIDO2 PRF behavior**. Code that worked against 5.4 may fail or behave differently on 5.7.

### Inventory pattern

```yaml
# .aiwg/security-engineering/supply-chain/hardware-pins.yaml
yubikey-5:
  tested-firmware: "5.4.3, 5.7.1"
  acceptable-firmware: ">=5.4.0, <6.0"
  test-vectors: "tests/yubikey-5-prf.txt"
  last-validated: "2026-04-15"

tpm-2.0:
  vendor: "Infineon"
  acceptable-firmware: ">=7.83"
  pcr-baseline: ".aiwg/security-engineering/chain-of-trust/pcr-baseline.yaml"
```

When a new firmware ships, run your test vectors against the new version before allowing it into production.

---

## Section 6: Worked examples

### Review M10 — SHA-256 manifest from poisoned apt source

Original: install-pkgs.sh verifies SHA-256 of each `.deb` file against a manifest produced by `apt-cache` at build time.

What this skill flags:

- Section 2 anti-pattern: verification within same trust domain as packaging
- Layer 2 attack: poisoned mirror produces consistent manifest + packages

Remediation:

- Pin to `snapshot.debian.org/archive/debian/<timestamp>/` URLs in install scripts
- Verify Debian `Release` file with explicit archive signing keys (`/usr/share/keyrings/debian-archive-keyring.gpg`)
- Generate `.deb` SHA manifest from the snapshot, NOT from `apt-cache`
- Commit the resulting manifest to a signed git repo
- Reproducibly rebuild the bootstrap partition; verify rebuild matches published

### Review H3 — `python-fido2` and transitive deps in PRF hot path

Original: bootstrap installs `python-fido2`, `cryptography`, `cffi`, `pyusb` from PyPI at first run.

What this skill flags:

- Layer 2 attack: PyPI compromise of any of 4+ packages affects PRF hot path
- Section 2: deps are not vendored OR hash-locked

Remediation (see also `auth-factor-design`):

- Replace `python-fido2` with `libfido2` C tools — drops Python from hot path
- If Python remains: vendor `python-fido2` + transitive deps with hash-locked wheels in bootstrap blob; verify per-wheel SHA-256 against manifest committed to signed repo; reproducible-build the bootstrap

### Review L6 — firmware version not documented

Original: design assumes "YubiKey 5 with FIDO2 PRF" without specifying firmware range.

What this skill flags:

- Section 5: hardware version not pinned

Remediation:

- Document tested firmware range (e.g., 5.4.0–5.7.x)
- Maintain test vectors in repo; run against any new firmware before adopting
- Operationally: standardize procurement to known-good firmware

---

## Section 7: Trust-boundary inventory

Mandatory exercise — for every external input to your build, document:

| Input | Source | Verification | Trust anchor |
|---|---|---|---|
| Source code (your repo) | git origin | signed commits + signed tags | dev signing keys |
| Source code (deps) | language registry | hash-locked manifest | dev publishes verified |
| Base OS packages | snapshot.debian.org | Debian archive key | embedded in keyring |
| Container base layer | OCI registry | image digest pinned | (none — ASSUMPTION) |
| Build CI | GitHub Actions | OIDC + SLSA L3 attestation | GitHub OIDC issuer |
| Hardware | physical procurement | (assumption: vendor not compromised) | (none — ASSUMPTION) |
| Firmware | (vendor) | version pinned, test vectors run | self-tested |

Rows with "ASSUMPTION" are explicitly accepted risks. Document why each assumption is acceptable.

---

## Section 8: Output format

When invoked as part of a review, produce findings in standard format. When authoring or updating, produce:

- `supply-chain-pins.yaml` — current pins for all layers
- `hardware-pins.yaml` — firmware versions tested
- `trust-boundary.md` — inventory and assumption acceptance

---

## Related

- **Existing**: `sdlc-complete/templates/security/sbom-guidance.md` (SBOM is upstream of this skill)
- **Existing**: `sdlc-complete/templates/security/dependency-policy-template.md` (this skill operationalizes the policy)
- **Companion skill**: `chain-of-trust-design` (Layer 3+4 — boot-time integrity)
- **Companion skill**: `physical-threat-modeling` (Layer 4 — hardware implant scenarios)

## Standards referenced

- SLSA Framework (`slsa.dev`)
- in-toto Specification (CMU)
- Reproducible Builds (`reproducible-builds.org`)
- Sigstore Cosign documentation
- NIST SP 800-204D — Strategies for Securing Software Supply Chains
- CISA Software Supply Chain Risk Management
- Trusted Platform Module 2.0 Library Specification (firmware identity)
