Software Supply Chain Security
The Threat Model
Software supply chain attacks exploit the trust relationships between your code and its dependencies. When Log4Shell (CVE-2021-44228) hit in December 2021, organizations discovered that a single transitive dependency, buried five levels deep in their dependency tree, gave attackers remote code execution on production servers. The SolarWinds attack showed that even trusted vendor build pipelines can be compromised to distribute malware to thousands of downstream customers.
The attack surface includes:
- Open source dependencies - Compromised packages uploaded to npm, PyPI, or Maven Central
- Build pipelines - Attackers modifying CI/CD configuration to inject malicious code during build
- Container images - Tampered base images or images pulled without signature verification
- Internal packages - Dependency confusion attacks that trick package managers into pulling malicious public packages instead of internal ones
- Developer tooling - Compromised IDE extensions, linters, or code formatters
SBOMs: Know What You Ship
A Software Bill of Materials (SBOM) is a machine-readable inventory of every component in your software artifact. It lists every dependency (direct and transitive), its version, its license, and its source. SBOMs are required by US Executive Order 14028 for software sold to the federal government, and increasingly expected by enterprise buyers.
Two dominant formats exist:
- SPDX - Linux Foundation standard, ISO/IEC 5962:2021. Detailed license compliance focus.
- CycloneDX - OWASP standard. Designed for security use cases with vulnerability correlation.
Generate SBOMs automatically in your CI pipeline using tools like syft (for container images), cdxgen (for application code), or built-in package manager commands (npm sbom, pip-audit). Store SBOMs alongside build artifacts and make them queryable. When the next Log4Shell drops, you need to answer "which of our services use this library?" in minutes, not days.
The SLSA Framework
SLSA (Supply-chain Levels for Software Artifacts, pronounced "salsa") defines four levels of increasing supply chain integrity:
| Level | Requirement | What It Proves |
|---|---|---|
| L1 | Build provenance exists | You know where and how the artifact was built |
| L2 | Signed provenance from a hosted build service | The build service attests to the build process |
| L3 | Hardened build platform with tamper-resistant provenance | The build cannot be influenced by developers after code review |
| L4 | Hermetic, reproducible builds with two-party review | The build is fully deterministic and independently verifiable |
Most organizations should target SLSA L2-L3. In practice, this means using a hosted CI service (GitHub Actions, Cloud Build), generating signed provenance attestations with each build, and ensuring that build configurations cannot be modified without code review.
Artifact Signing and Verification
Container images and binaries should be cryptographically signed so that deployment systems can verify they came from your CI pipeline, not from an attacker.
Sigstore is the emerging standard for keyless signing:
cosign sign- Signs a container image using OIDC identity (no long-lived keys to manage)- The signature and certificate are stored in Rekor, a public transparency log
- At deployment time, Kubernetes admission controllers (like Kyverno or Connaisseur) verify the signature before allowing the image to run
This creates an unbroken chain of trust: code is reviewed, merged, built by CI, signed, and verified at deployment. Any tampering at any stage breaks the chain.
Dependency Scanning and Management
Vulnerability scanning must cover the entire dependency tree, not just direct imports:
- SCA tools - Snyk, Grype, Trivy, or Dependabot scan dependencies against CVE databases and produce actionable reports.
- Pin everything - Use lockfiles (
package-lock.json,poetry.lock,go.sum) and pin container base image digests (node:20@sha256:abc...) rather than mutable tags. - Automate updates - Dependabot or Renovate Bot creates PRs for dependency updates. Review them promptly. Stale dependencies accumulate vulnerabilities.
- Namespace internal packages - To prevent dependency confusion attacks, use scoped packages (
@company/utils) on npm or a private registry with priority over public sources. - Evaluate before adopting - Before adding a new dependency, check its maintenance status, download count, known vulnerabilities, and whether it is actually necessary. Every dependency you add expands your supply chain attack surface.
Key Points
- •An SBOM (Software Bill of Materials) is a machine-readable inventory of every component in your software. It is the foundation of supply chain security
- •The SLSA framework defines four levels of supply chain integrity, from basic build provenance (L1) to hermetic, reproducible builds (L4)
- •Dependency confusion attacks exploit package managers that check internal registries before public ones. Namespace your internal packages
- •Artifact signing with Sigstore/cosign provides cryptographic proof that a container image was built by your CI pipeline
- •Log4Shell proved that transitive dependencies are the real threat. You must scan the entire dependency tree, not just direct imports
Common Mistakes
- ✗Only scanning direct dependencies and ignoring transitive dependencies where most supply chain vulnerabilities hide
- ✗Generating SBOMs as a one-time exercise instead of producing them automatically with every build
- ✗Trusting container base images without verifying their signatures or scanning them for vulnerabilities
- ✗Not pinning dependency versions, allowing silent updates that could introduce compromised packages