Frontend Labs
⋯

Chapter 47 — Supply chain and the code you didn't write

In one sentence

Most of your application is third-party code — dependencies, base images, build tools, CI plugins, CDNs — and each is a path into production that you must inventory, pin, verify, and monitor.

The attack surface

   DIRECT DEPENDENCIES        the 20 packages you chose
   TRANSITIVE DEPENDENCIES    the 800 they pulled in (this is where it hides)
   BUILD-TIME                 compilers, bundlers, codegen, CI plugins,
                              GitHub Actions, pre/post-install scripts
   BASE IMAGES                FROM node:20 -> a whole OS you didn't audit
   DEV TOOLS                  IDE extensions, linters, test frameworks
   RUNTIME PULLS              CDN <script>, fonts, analytics, tag managers
   INFRASTRUCTURE             Terraform modules, Helm charts, Ansible roles

How supply-chain attacks actually happen

   TYPOSQUATTING / name confusion  reqeusts, python-dateutil vs
     python3-dateutil, lodahs. Install-time scripts run as you.
   DEPENDENCY CONFUSION  publish a PUBLIC package with the same name as a
     company's PRIVATE one + higher version -> the resolver picks the
     public one (Alex Birsan, 2021 -- hit Apple, Microsoft, dozens more).
   COMPROMISED MAINTAINER  stolen npm/PyPI creds, or a maintainer goes
     rogue (event-stream 2018; ua-parser-js 2021; a burnt-out maintainer
     hands over the keys).
   MALICIOUS UPDATE to a legit package  (xz-utils / liblzma backdoor,
     2024 -- a multi-year social-engineering campaign to plant an sshd
     backdoor; caught by luck).
   BUILD SYSTEM COMPROMISE  SolarWinds (2020) -- malware injected into the
     build, so the SIGNED official artifact was backdoored.
   CI/CD  leaked tokens, `pull_request_target` misuse, poisoned caches,
     self-hosted runner takeover, a malicious Action pinned to a mutable tag.
   PROTESTWARE  a maintainer ships sabotage (node-ipc, 2022).

The defences (SLSA-style, layered)

   INVENTORY
   [ ] Generate an SBOM (CycloneDX / SPDX) per build. Know every component
       and version in prod.  (syft, cdxgen, `npm sbom`, trivy)

   PIN & LOCK
   [ ] Commit lockfiles (package-lock.json, poetry.lock, go.sum, Cargo.lock).
   [ ] Pin GitHub Actions to a full commit SHA, not @v3 (mutable tag).
   [ ] Pin base images by DIGEST (FROM node:20@sha256:...), not tag.
   [ ] Disable/participate cautiously in install scripts
       (npm --ignore-scripts where feasible; vet the exceptions).

   VERIFY
   [ ] Signature/provenance verification: npm provenance, PyPI Trusted
       Publishing + attestations, Sigstore/cosign for containers, SLSA
       provenance, `cargo-vet`/`cargo-crev`.
   [ ] Checksum-pin where signatures aren't available.
   [ ] Use a PRIVATE REGISTRY / pull-through proxy (Artifactory, GAR,
       Verdaccio) with an allowlist; block direct public pulls from prod
       builds. Scope internal names to defeat dependency confusion
       (npm scopes, explicit index-url, no implicit fallback).

   SCAN & MONITOR
   [ ] SCA in CI: Dependabot/Renovate, `npm audit`, `pip-audit`,
       `osv-scanner`, Trivy, Snyk/Grype -> fail the build on known-critical
       CVEs (with a triage/allowlist process so it's not ignored).
   [ ] Watch advisories: GitHub Advisory DB, OSV, your ecosystem's feeds.
   [ ] Renovate/Dependabot for timely, reviewed updates (stale deps are
       the more common real problem than malicious ones).

   CONTAIN
   [ ] Least privilege for CI: short-lived OIDC creds, no long-lived
       secrets, minimal token scopes, protected branches, required
       reviews, environment protection rules.
   [ ] Reproducible / hermetic builds where you can (SLSA L3+).
   [ ] Runtime: minimal/distroless images, non-root, read-only FS,
       egress filtering (a backdoored dep still has to call home).
   [ ] Subresource Integrity (SRI) for any CDN <script>/<link>, or better,
       self-host.

   DATA & CODE INTEGRITY (OWASP A08)
   [ ] Signed releases (Ch 22/26 tool). Verify before deploy.
   [ ] No insecure deserialization of untrusted data (pickle, Java
       ObjectInputStream, PHP unserialize, YAML unsafe_load, .NET
       BinaryFormatter) -> RCE. Use JSON / schema-validated formats.
   [ ] Protect the update channel: signed, versioned, rollback-safe (TUF).

Practice (40 min)

# 1. See how deep the tree really goes
npm ls --all 2>/dev/null | wc -l          # or: npm ls --all --json | jq '..|.dependencies?|keys?' 
pipdeptree 2>/dev/null | wc -l
go list -m all | wc -l

# 2. Generate an SBOM and scan it
syft dir:. -o cyclonedx-json > sbom.json    # or: trivy fs --format cyclonedx -o sbom.json .
grype sbom:sbom.json                        # or: osv-scanner --sbom sbom.json
trivy fs --scanners vuln,secret,misconfig .

# 3. Audit with the ecosystem tools
npm audit --audit-level=high
pip-audit -r requirements.txt
osv-scanner -r .
cargo audit          # if Rust

# 4. Find unpinned CI and images (your repos)
grep -rnE 'uses: .*@(v?[0-9]+|main|master)$' .github/workflows/    # mutable Action refs
grep -rn 'FROM .*:[^@]*$' Dockerfile*                              # tag, not digest

# 5. Dependency-confusion check: do you have internal package names that
#    are NOT scoped / could be resolved from the public registry?
cat package.json | jq '.dependencies|keys[]' | grep -v '^"@'       # unscoped deps

# 6. SRI for a CDN script:
#   printf '' | openssl dgst -sha384 -binary < jquery.min.js | openssl base64 -A
#   <script src="..." integrity="sha384-..." crossorigin="anonymous"></script>

Mini-project (60 min): supply-chain gate for SecureShop

   Add to SecureShop's CI a "supply-chain gate" stage that:
     1. Builds an SBOM (syft) and stores it as an artifact per release.
     2. Runs osv-scanner + trivy; FAILS on CRITICAL/HIGH with no
        documented, time-boxed exception file (.security/allow.yml with
        reason + expiry + owner).
     3. Verifies all GitHub Actions are pinned to SHAs (a lint step).
     4. Verifies the base image is pinned by digest.
     5. Signs the built container with cosign and generates SLSA
        provenance; the deploy step verifies the signature before rollout.
     6. Emits a short report to ~/sec-lab/reports/part10-supplychain.md:
        dependency count (direct/transitive), findings, exceptions,
        what the gate blocked.

Common confusions

  • "npm audit is noise." Much of it is low-severity transitive stuff — but triage it with a process (allowlist + expiry), don't blanket-ignore. The one real RCE will be in there too.
  • "Lockfile = safe." Lockfiles pin versions (integrity), which is essential, but a pinned version can still be malicious (compromised release). Add signature/provenance verification and scanning.
  • "We only use big, popular packages." event-stream, ua-parser-js, xz-utils, and left-pad were all popular. Popularity is not safety; maintenance health and provenance are.
  • "Our code is signed, so the pipeline is secure." SolarWinds signed the backdoored artifact. Protect the build, not just the release step.
  • "Pinning Actions to @v3 is pinning." Tags are mutable. Pin to the commit SHA.
  • "SCA covers us." SCA finds known CVEs. It won't catch a fresh malicious package or a novel backdoor. Layers: inventory + pin + verify + scan + contain.

Check yourself

  1. Where in the dependency tree does most hidden risk live, and why?
  2. Explain dependency confusion and one way to prevent it.
  3. What is an SBOM and why generate one per build?
  4. Why pin GitHub Actions and base images by digest/SHA rather than tag?
  5. What did SolarWinds teach that "sign your releases" alone doesn't cover?
  6. Name a deserialization function in a language you use that can lead to RCE, and the safe alternative.

Further reading

  • Framework: SLSA (slsa.dev) — supply-chain integrity levels; start with the "get started" and the threats page.
  • Project: Sigstore / cosign (sigstore.dev); OSV and osv-scanner (osv.dev); Syft/Grype (Anchore); Trivy (Aqua).
  • Guidance: OWASP "Software Supply Chain Security" and the CNCF "Software Supply Chain Best Practices" paper; SP 800-204D; CISA/NSA "Securing the Software Supply Chain" series.
  • Write-ups: Alex Birsan, "Dependency Confusion" (2021); the xz-utils backdoor analyses (Andres Freund's disclosure + timelines); the SolarWinds SUNBURST technical reports.
  • Cheat sheet: OWASP "Vulnerable Dependency Management" and "Deserialization".

Generated from real-life-guide.md · 8 Oct 2026 16:36