The SolarWinds attack revealed how vulnerable software supply chains are. A compromised build system distributed malware to thousands of organizations through trusted update channels. This changes how we must think about software security.
Here’s how to secure your software supply chain.
The Supply Chain Attack Surface
Where Attacks Happen
┌─────────────────────────────────────────────────────────────────┐
│ Software Supply Chain │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Source Code ──► Dependencies ──► Build ──► Package ──► Deploy │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │
│ Compromised Malicious Injected Tampered Replaced │
│ developer package malware artifact binary │
│ account │
│ │
└─────────────────────────────────────────────────────────────────┘
Attack Vectors
Source code:
- Compromised developer credentials
- Malicious pull requests
- IDE plugin attacks
Dependencies:
- Typosquatting packages
- Dependency confusion
- Compromised maintainer accounts
Build systems:
- Compromised CI/CD
- Injected build steps
- Poisoned build caches
Distribution:
- Man-in-the-middle attacks
- Compromised registries
- DNS hijacking
Software Bill of Materials (SBOM)
What Is an SBOM
An inventory of all software components:
{
"bomFormat": "CycloneDX",
"specVersion": "1.4",
"version": 1,
"metadata": {
"component": {
"type": "application",
"name": "my-application",
"version": "1.0.0"
}
},
"components": [
{
"type": "library",
"name": "lodash",
"version": "4.17.21",
"purl": "pkg:npm/lodash@4.17.21",
"hashes": [
{
"alg": "SHA-256",
"content": "cc6c1e..."
}
],
"licenses": [
{
"license": { "id": "MIT" }
}
]
}
]
}
Generating SBOMs
# For Node.js
npx @cyclonedx/cdxgen -o sbom.json
# For Go
cyclonedx-gomod mod -json > sbom.json
# For containers
syft myimage:tag -o cyclonedx-json > sbom.json
# For general use
trivy image --format cyclonedx myimage:tag > sbom.json
Using SBOMs
uses:
vulnerability_tracking:
- Know what's affected when CVE announced
- Automated alerts for new vulnerabilities
- Prioritize remediation
license_compliance:
- Track license obligations
- Detect problematic licenses
- Audit trail for legal
incident_response:
- "Are we affected by log4j?"
- Instant answer from SBOM database
- Identify all affected systems
procurement:
- Evaluate third-party software
- Risk assessment
- Vendor management
Build System Security
Secure Build Principles
principles:
hermetic_builds:
- No network access during build
- All dependencies pre-fetched
- Reproducible outputs
minimal_access:
- Build system can't access production
- Credentials are scoped and short-lived
- Audit all access
integrity_verification:
- Verify source before building
- Verify dependencies before including
- Sign outputs
transparency:
- Log all build activities
- Monitor for anomalies
- Alert on deviations
Build Isolation
# Isolated build environment
build_environment:
container:
image: build-env:v1 # Verified, controlled image
network: none # No network access
read_only: true # Immutable filesystem
capabilities: [] # Drop all capabilities
inputs:
- source: verified git checkout
- dependencies: pre-fetched, verified
outputs:
- artifacts: signed before distribution
- sbom: generated and stored
- attestation: build provenance recorded
SLSA Framework
Supply-chain Levels for Software Artifacts:
Level 1: Documentation of build process
Level 2: Tamper resistance of build service
Level 3: Tamper resistance of source/build
Level 4: Two-person review, hermetic builds
# SLSA Level 3+ practices
practices:
source:
- All changes reviewed
- Signed commits
- Protected branches
build:
- Ephemeral build environments
- Hermetic builds
- Reproducible builds
- Build provenance generated
provenance:
- What source was built
- What builder was used
- What dependencies included
- Signed attestation
Dependency Security
Dependency Verification
# Lock files capture exact versions and hashes
# package-lock.json, go.sum, requirements.txt with hashes
# Verify integrity
npm ci --ignore-scripts # Install from lock file, no arbitrary scripts
go mod verify # Verify checksums
# Audit for vulnerabilities
npm audit
go list -m -json all | go-mod-outdated -update
Private Registry Mirroring
# Mirror public packages internally
registry_strategy:
external:
- npmjs.com
- pypi.org
- proxy.golang.org
internal_mirror:
- Nexus/Artifactory
- Cache verified packages
- Scan before caching
- Audit access
policy:
- Only use mirrored packages
- Block direct external access
- Review before adding new packages
Dependency Pinning
# Pin to exact versions with hashes
# requirements.txt
requests==2.26.0 \
--hash=sha256:6c1246...
# package-lock.json
{
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-..."
}
}
Code Signing
Sign Build Outputs
# Sign container images with Sigstore
cosign sign --key cosign.key myregistry.io/myapp:v1.0.0
# Verify before deploying
cosign verify --key cosign.pub myregistry.io/myapp:v1.0.0
Keyless Signing
# Using Sigstore Keyless (OIDC identity)
cosign sign myregistry.io/myapp:v1.0.0
# Uses OIDC identity (GitHub, Google, etc.)
# No key management required
# Verify
cosign verify \
--certificate-identity-regexp='.*@mycompany.com' \
--certificate-oidc-issuer=https://accounts.google.com \
myregistry.io/myapp:v1.0.0
Admission Control
# Kubernetes policy: only signed images
apiVersion: policy.sigstore.dev/v1alpha1
kind: ClusterImagePolicy
metadata:
name: require-signatures
spec:
images:
- glob: "**"
authorities:
- keyless:
url: https://fulcio.sigstore.dev
identities:
- issuer: https://accounts.google.com
subject: build-service@mycompany.iam.gserviceaccount.com
Monitoring and Detection
Build Monitoring
alerts:
- name: UnusualBuildActivity
condition: build outside normal hours
action: review and alert
- name: NewDependencyAdded
condition: dependency not in approved list
action: security review required
- name: BuildOutputChanged
condition: same inputs, different outputs
action: investigate immediately
- name: LongBuildDuration
condition: build takes 2x normal time
action: investigate (possible injection)
Artifact Verification
# In deployment pipeline
steps:
- name: Verify signature
run: cosign verify --key cosign.pub $IMAGE
- name: Check SBOM vulnerabilities
run: grype sbom:$SBOM_PATH --fail-on high
- name: Verify attestations
run: cosign verify-attestation --key cosign.pub $IMAGE
Implementation Roadmap
Phase 1: Visibility
- [ ] Generate SBOMs for all applications
- [ ] Inventory all dependencies
- [ ] Map build processes
- [ ] Identify critical paths
Phase 2: Hardening
- [ ] Implement dependency pinning
- [ ] Enable vulnerability scanning
- [ ] Isolate build environments
- [ ] Add code signing
Phase 3: Verification
- [ ] Require signatures for deployment
- [ ] Implement admission control
- [ ] Add provenance verification
- [ ] Continuous monitoring
Key Takeaways
- Software supply chain is a critical attack vector; SolarWinds proved it
- SBOMs enable visibility into what’s in your software
- Build systems need production-level security; they’re high-value targets
- Hermetic builds prevent injection; no network access during build
- Verify dependencies with checksums and signatures
- Sign build outputs; verify before deployment
- SLSA framework provides maturity levels for supply chain security
- Monitor build systems for anomalies; unusual activity could indicate compromise
- Start with visibility (SBOMs), then harden, then verify
Supply chain security is no longer optional. The threat is real, the attacks are sophisticated, and the consequences are severe.