Dependency and Software-Supply-Chain Security

Applications inherit risk from packages, build tools, plugins, containers, CI actions, compiler toolchains, firmware libraries, and update channels.

14.1 Why supply-chain security matters

Applications inherit risk from packages, build tools, plugins, containers, CI actions, compiler toolchains, firmware libraries, and update channels. A dependency may be vulnerable, abandoned, compromised, or replaced by a malicious lookalike.

14.2 Dependency hygiene

Maintain a complete direct and transitive dependency inventory.

Prefer maintained packages with clear ownership and release history.

Pin or constrain versions according to the ecosystem's reproducibility model.

Commit lockfiles where appropriate.

Review changes to package manifests and lockfiles.

Remove unused dependencies.

Monitor advisories and establish remediation SLAs.

Verify package source, integrity, signatures, and provenance where supported.

Do not blindly auto-upgrade production dependencies without tests.

14.3 Software Bill of Materials (SBOM)

An SBOM records components and versions in a software artifact. Formats include SPDX and CycloneDX. SBOMs help incident response and vulnerability triage but do not prove components are safe or that the inventory is complete.

14.4 Provenance and reproducible builds

Restrict who can modify release workflows.

Use protected branches and reviewed changes.

Pin third-party CI actions to immutable revisions where appropriate.

Separate build and deployment permissions.

Protect signing keys.

Produce build provenance and verify artifacts where tooling supports it.

Make builds reproducible where feasible.

Promote the same verified artifact through environments rather than rebuilding untracked variants.

Verifying an artifact digest Output (CPython 3.13.1): A digest only helps if the expected value comes from somewhere the attacker cannot change — signed release metadata, a lockfile under review, or a provenance attestation. Lockfiles in npm, pip (--require-hashes), Cargo and Go modules record digests for exactly this reason.

import hashlib

artifact = b"sampleapp-api 1.4.2 build output"          # stands in for a downloaded file
published = hashlib.sha256(artifact).hexdigest()           # digest from the signed release metadata

def verify_artifact(data: bytes, expected_hex: str) -> bool:
    return hashlib.sha256(data).hexdigest() == expected_hex

print("sha256:", published[:16] + "…")
print("matches published digest:", verify_artifact(artifact, published))
print("one byte changed:", verify_artifact(artifact[:-1] + b"?", published))
sha256: 25eed1349e23139a…
matches published digest: True
one byte changed: False

14.5 Secret scanning

Scan source history and current files. If a secret is committed, deleting the line is not enough: revoke or rotate the credential, review access logs, and assess possible exposure. Use pre-commit and CI checks plus managed runtime secrets.

What a basic secret scanner looks for Output (CPython 3.13.1):

All values here are fake fixtures. Real scanners (gitleaks, trufflehog, GitHub secret scanning and others) combine provider-specific patterns, entropy and verification. If a real secret is found in history, revoke and rotate it — deleting the line does not remove it from clones and caches.

import math
import re
from collections import Counter

PATTERNS = {
    "private key block": re.compile(r"-----BEGIN [A-Z ]*PRIVATE KEY-----"),
    "assignment of a credential": re.compile(r"(?i)\b(api[_-]?key|secret|password|token)\b\s*[:=]\s*['\"]([^'\"]{8,})['\"]"),
}

def entropy(s: str) -> float:
    counts = Counter(s)
    return -sum(c / len(s) * math.log2(c / len(s)) for c in counts.values())

sample = '''
timeout = 30
api_key = "EXAMPLE-ONLY-not-a-real-key-1234"
password = "changeme"
token = "q8Zr1vT0mWc3Xk9LpB2nYs7Hd4Fa6Je5"
'''
for lineno, line in enumerate(sample.strip().splitlines(), 1):
    for name, pattern in PATTERNS.items():
        m = pattern.search(line)
        if m:
            value = m.group(m.lastindex or 0)
            print(f"line {lineno}: {name} ({m.group(1)}), entropy {entropy(value):.2f} bits/char")
line 2: assignment of a credential (api_key), entropy 4.27 bits/char
line 3: assignment of a credential (password), entropy 2.75 bits/char
line 4: assignment of a credential (token), entropy 5.00 bits/char

14.6 Vulnerability response

Confirm the affected component and version.

Determine reachability and actual exposure.

Assess exploitability and business impact.

Apply a patched version or documented mitigation.

Run regression and compatibility tests.

Deploy through controlled release.

Verify the vulnerable version is no longer present.

Record the decision and residual risk.

14.7 License and provenance review

Security engineering also needs legal and operational visibility: review licenses, source provenance, maintenance status, abandoned dependencies, build scripts, and packages with install-time code.

Exercise

Generate a dependency inventory and SBOM for a sample project. Identify one dependency with an advisory and document a safe remediation and verification plan.

Quiz

? What does an SBOM provide?
+ An inventory of components and versions in an artifact, useful for triage :: Correct — and that is its limit.
- Proof that all components are safe :: It lists components; it does not vet them.
- Automatic patching :: It informs patching; it does not perform it.
- A guarantee that the inventory is complete :: Tools can miss vendored or dynamically loaded code.

? An API key was committed and then removed in the next commit. What must happen?
- Nothing — it is no longer in the code. :: It remains in history, forks, clones and caches.
+ Revoke or rotate the key, review its usage logs and assess exposure. :: Treat it as compromised.
- Rewrite history and keep the key. :: Copies may already exist.
- Make the repository private. :: Earlier copies may already exist.

? Which practices strengthen build provenance? (select all that apply)
+ Pin third-party CI actions to immutable revisions :: A moving tag can change underneath you.
+ Promote the same verified artifact through environments :: Rebuilding creates untracked variants.
+ Protect signing keys and separate build from deploy permissions :: Limits what one compromised step can do.
- Let any contributor 
…