Supply Chain Security in GitHub Actions: Stopping the Next SolarWinds
Use SBOMs, pinned actions, and signed commits in GitHub Actions to guarantee code provenance from commit to container — the cheap version of supply-chain security.
SolarWinds didn't happen because attackers were geniuses. It happened because the build pipeline was a trusted black box that nobody could attest to after the fact. GitHub Actions, used carelessly, is exactly the same shape.
Here's the cheap, three-control version of supply-chain security that closes 80% of the gap.
Control 1: Pin every action to a SHA
uses: actions/checkout@v4 resolves to a tag the maintainer can re-point. uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab is immutable. A compromised maintainer cannot retroactively change what you ran.
Dependabot has a package-ecosystem: github-actions mode that opens PRs to bump SHAs while keeping them pinned. There is no excuse for @v4 in 2025.
Control 2: Generate and store an SBOM per artifact
- name: Generate SBOM
uses: anchore/sbom-action@<sha>
with:
image: ${{ env.IMAGE_URI }}
format: spdx-json
output-file: sbom.spdx.json
- name: Attach SBOM to image
run: cosign attest --predicate sbom.spdx.json --type spdx ${{ env.IMAGE_URI }}
The SBOM tells you what's actually in the image. When the next Log4Shell drops, "do we use log4j 2.14?" is a grep against your SBOM archive, not a panicked dependency audit across 60 repos.
Control 3: Sign commits and sign images
- Commit signing with Sigstore's
gitsignties every commit to a verified human identity, not a Git config string anyone can spoof. - Image signing with
cosignlets the deployer verify the image was built by your pipeline before it runs:
cosign verify \
--certificate-identity-regexp 'https://github.com/acme/.+' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
$IMAGE
Wire that into an admission controller (Kyverno, Gatekeeper) and unsigned images simply don't deploy.
What the auditor sees
- For any deployed artifact: a signed SBOM + provenance attestation chain back to a specific commit SHA, a specific workflow run, and a specific GitHub identity.
- A negative test: deploying an unsigned image gets rejected, with a screenshot.
- A Dependabot graph showing actions pinned at SHAs with managed update PRs.
This isn't NSA-grade supply chain security. It's the minimum that turns "we trust GitHub" into "we can prove what we built and who built it." That's the entire SolarWinds gap, closed for the cost of three YAML steps and a Cosign install.
Further reading: SLSA framework.