Skip to content

Expert · DevSecOps · topic 48 of 53 · 35 min

Software supply chain security

Explanation

Your software is mostly other people's code: libraries, base images, build tools and CI actions. Supply chain security means knowing what is inside (SCA and SBOMs), scanning code, images and infrastructure files, checking where an artefact came from (signing and provenance), and pinning versions so nothing changes under you.

What is the software supply chain?

The software supply chain is everything that goes into what you ship: your own code, the open-source packages you install, the packages those packages install (transitive dependencies), the base image in your Dockerfile, the build tools, the CI runners and the reusable actions in your workflows. A small Node.js API with 20 direct dependencies often pulls in several hundred transitive ones. Any of them can carry a vulnerability (a weakness an attacker could use) or, rarely, malicious code.

Real incidents show why this matters. Log4Shell (December 2021) was a critical flaw in the Log4j logging library used inside thousands of Java products. In 2024 a backdoor was found in the xz compression tool before it reached most stable Linux releases. In March 2025 the tags of a popular GitHub Action, tj-actions/changed-files, were moved to a malicious commit that printed CI secrets into build logs.

SCA and lockfiles

SCA (software composition analysis) lists your dependencies and compares them with vulnerability databases, such as CVE records, the GitHub Advisory Database and OSV. A CVE (Common Vulnerabilities and Exposures) ID is a public name for one known vulnerability, like CVE-2021-44228 for Log4Shell. Tools include Dependabot, Snyk, OWASP Dependency-Check, Trivy, npm audit and pip-audit.

A lockfile (package-lock.json, poetry.lock, go.sum) records the exact version and a hash of every dependency, including transitive ones. Commit it, and install from it in CI (npm ci rather than npm install), so every build uses exactly the same, checked packages.

Typosquatting and dependency confusion: the defences

Typosquatting is publishing a harmful package with a name close to a popular one, hoping someone mistypes it. Dependency confusion happens when a company uses a private package name, and a public package with the same name and a higher version gets installed instead because the package manager checks the public registry too.

  • Use scoped or namespaced packages for internal code (for example @acme/payments) and point that scope at your private registry.
  • Use one internal registry proxy (such as Artifactory, Nexus, GitHub Packages or Azure Artifacts) as the only source for builds.
  • Commit lockfiles with integrity hashes, and review every new dependency in the pull request: who maintains it, how popular it is, when it was last updated.

The scanning family

TypeWhat it checksWhen it runsExamples
SAST (static analysis)Your source code, without running itEvery pull requestSemgrep, SonarQube, CodeQL
SCADependencies and their known vulnerabilitiesEvery pull request and dailyDependabot, Snyk, OWASP Dependency-Check, Trivy
Secret scanningKeys and tokens in code and historyPre-commit and every pushgitleaks, GitHub secret scanning
Container image scanningOS packages and libraries inside an imageAfter the image is built, and on a scheduleTrivy, Grype, Docker Scout
IaC scanningMisconfiguration in Terraform, Kubernetes YAML, DockerfilesEvery pull requestCheckov, Trivy (tfsec is now part of Trivy)
DAST (dynamic analysis)A running app, tested from the outsideAgainst staging, before releaseZAP
Careful: Run DAST only against your own applications, or with written permission from the owner. Scanning or probing someone else's system without permission is an offence in India under the Information Technology Act, 2000 (sections 43 and 66), and in most other countries. Cloud providers also publish rules about what testing is allowed on their platforms.

SBOMs: the ingredients list

An SBOM (software bill of materials) is a machine-readable list of every component and version inside your software, like the ingredients list on a food packet. The two main formats are SPDX (from the Linux Foundation, also an ISO standard) and CycloneDX (from OWASP). Governments and large customers increasingly ask for SBOMs: the US government pushed for them after a 2021 executive order, CERT-In published SBOM guidelines in India in 2024, and the EU Cyber Resilience Act requires them from product makers. The practical reason is simple: when the next Log4Shell is announced, an SBOM answers "are we affected?" in minutes instead of days.

bash
syft ghcr.io/acme/canteen-api:3f9c2ab -o spdx-json > sbom.spdx.json      # make an SPDX SBOM
trivy image --format cyclonedx --output sbom.cdx.json ghcr.io/acme/canteen-api:3f9c2ab
grype sbom:./sbom.spdx.json                                               # scan the SBOM for known vulnerabilities
Syft and Trivy create SBOMs; Grype or Trivy can scan them later without the image.

Signing, provenance and SLSA

Signing proves an image came from you and was not changed. cosign, from the Sigstore project, signs container images and stores the signature next to the image in the registry. It also supports keyless signing, where the CI job's OIDC identity is used instead of a long-lived key and the signature is recorded in a public transparency log. Your cluster or deploy job then verifies the signature before running the image.

bash
cosign sign --key cosign.key ghcr.io/acme/canteen-api@sha256:4a1f...e9
cosign verify --key cosign.pub ghcr.io/acme/canteen-api@sha256:4a1f...e9
Sign by digest, not by tag, so the signature covers exactly one image.

Provenance is a signed record of how an artefact was built: which source commit, which build system, which steps. SLSA (Supply-chain Levels for Software Artifacts, said "salsa") is a framework whose build levels describe how trustworthy that provenance is, from "provenance exists" up to "built on a hardened, isolated build platform".

Pin by digest, update with bots

A tag like node:22-slim or actions/checkout@v7 can be moved to point at different content. A digest (sha256:...) or a full commit SHA cannot. Pin base images by digest and third-party actions by full commit SHA, with the version in a comment. Then let Dependabot or Renovate open small pull requests to update the pins, so you stay pinned and current.

yaml
# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"
  - package-ecosystem: "docker"
    directory: "/"
    schedule:
      interval: "weekly"
Dependabot keeps npm packages, workflow actions and Dockerfile base images up to date.
Careful: Common mistakes: using npm install instead of npm ci in CI; using third-party actions by a moving tag; scanning images once and never again (new CVEs appear every day for old images); letting update pull requests pile up unmerged. Fix: lockfiles plus npm ci, pin by SHA or digest, schedule rescans, and merge small updates weekly.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Software supply chain security · 1/7

Your app = your code + everyone else's

Your software is mostly other people's code: libraries, the libraries they use, base images, build tools and CI actions. That is your supply chain.

Prefer a video by a teacher? Find free videos on “software supply chain security sbom cosign slsa explained” on YouTube ↗

In real life: Log4Shell week at an Indian IT services company

When Log4Shell was announced in December 2021, a Chennai-based services company had to tell dozens of clients, including banks, whether they were affected. Teams with SBOMs and SCA dashboards searched for log4j-core and had a list of affected versions and projects within hours. Teams without them logged in to servers and searched JAR files by hand for days. Afterwards the company made an SBOM a required output of every build and stored it with each release.

Practice (0/3 done)

Task 1 · Question

Which kind of tool finds a vulnerable version of a library listed in your package-lock.json?

Task 2 · Code · Python

Write affected(components, vulns). components is an SBOM-like list of {"name": ..., "version": "1.2.3"}. vulns is a list of {"id": ..., "package": ..., "range": ...} where range is one or more conditions joined by commas, like "<1.2.3" or ">=2.0.0,<2.4.1". Operators: <, <=, >, >=, ==. Return a sorted list of (name, version, vuln_id) for every component whose version matches ALL conditions of a vulnerability for the same package. Compare versions as numbers, not text: 2.10.0 is newer than 2.9.0. Also write parse_version(text) that returns a tuple of 3 ints, padding missing parts with 0 ("1.2" gives (1, 2, 0)).

Task 3 · Practice

Add supply chain checks to a GitHub Actions workflow for a Node.js API that builds a Docker image. Write the job steps (YAML or a clear list) and say which steps should FAIL the build and which should only report.

Quick quiz

Question 1

1.What is an SBOM?

Question 2

2.Why pin a GitHub Action by full commit SHA instead of a tag like @v4?

Question 3

3.Which tool is used to sign and verify container images?

Question 4

4.When is it acceptable to run a DAST scan such as ZAP against a website?

Question 5

5.Which scanner category finds a public S3 bucket defined in a Terraform file before it is created?

Read more (free)

Before this, learn

This topic builds on these. If something here feels new, open them first.

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What is an SBOM?

Answer: A list of every component and version inside a piece of software

A software bill of materials is the ingredients list of your software, in formats like SPDX or CycloneDX.

Why pin a GitHub Action by full commit SHA instead of a tag like @v4?

Answer: A tag can be moved to different code; a commit SHA always means the same code

In the tj-actions incident, existing tags were moved to a malicious commit. A SHA cannot be moved.

Which tool is used to sign and verify container images?

Answer: cosign

cosign, from the Sigstore project, signs images and verifies signatures.

When is it acceptable to run a DAST scan such as ZAP against a website?

Answer: Only on your own application or with written permission from the owner

Testing other people's systems without permission is an offence, in India under the IT Act 2000 (sections 43 and 66).

Which scanner category finds a public S3 bucket defined in a Terraform file before it is created?

Answer: IaC scanning (for example Checkov or Trivy)

IaC scanners read Terraform and Kubernetes files and flag risky settings before anything is deployed.

What does pinning an image by digest (image@sha256:...) give you?Related

Answer: The exact same image content every time, because a digest cannot be moved like a tag

A digest is a content hash. Remember to update pins on a schedule so patches still arrive.

From Image and container security

Why pin a third-party action to a full commit SHA instead of a tag like v2?Related

Answer: A tag can be moved to different code later; a commit SHA always means the same code

Pinning to a SHA protects you if the action's repository is compromised and a tag is moved.

From GitHub Actions

What is Google Cloud's current registry for container images?Related

Answer: Artifact Registry

Artifact Registry replaced Container Registry.

From Containers, images and registries

Why pin the version of a Registry module?Related

Answer: So an upstream update cannot change your infrastructure without review

Pinning means updates happen only when you change the version in a reviewed pull request.

From Modules, environments and Terraform in CI

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 1 more topic in “DevSecOps” before its exam: Kubernetes security.
  2. Module 11 exam: DevSecOps · 12 questions · 20 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, GitOps, platform engineering and DevOps careers. 53 topics left in the course before the final exam.

← Previous: Secrets management