iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

A06 Vulnerable Components

A06:2021 Vulnerable and Outdated Components. Most apps ship with hundreds of third-party packages. Each one is a supply chain that can carry a known CVE into production. The defense is boring and repeatable: inventory, monitor, patch.

SBOM, scanning, patch hygiene

EXAMPLE
// SCENARIO — keeping a real app on top of its dependencies.
// This is defensive engineering, not exploit content.

// ─── STEP 1 — Inventory (Software Bill of Materials) ───────────
// You cannot patch what you cannot see.

// Node
npm ls --all --json > sbom.json                       # tree
npx @cyclonedx/cyclonedx-npm --output-file sbom.cdx.json  # CycloneDX

// Python
pip freeze > requirements.lock
syft packages dir:. -o cyclonedx-json > sbom.json     # syft, language-agnostic

// Containers
syft packages docker:myapp:1.2.3 -o cyclonedx-json > image-sbom.json

// Store SBOMs as build artifacts — every release ships with its inventory.

// ─── STEP 2 — Scan against known vulnerabilities ───────────────
// Pick at least one of: GitHub Dependabot, Snyk, Trivy, OSV-Scanner, npm audit

npm audit --omit=dev
npm audit --audit-level=high --json | jq '.vulnerabilities | keys'

// Containers — fail the build on HIGH/CRITICAL
trivy image --severity HIGH,CRITICAL --exit-code 1 myapp:1.2.3

// Language-agnostic via SBOM
grype sbom:./sbom.json --fail-on high
osv-scanner --lockfile package-lock.json --lockfile poetry.lock

// ─── STEP 3 — Wire it into CI ──────────────────────────────────
// .github/workflows/security.yml
name: security
on: [push, pull_request]
jobs:
    scan:
        runs-on: ubuntu-latest
        steps:
            - uses: actions/checkout@v4
            - uses: actions/setup-node@v4
            - run: npm ci
            - run: npm audit --omit=dev --audit-level=high
            - uses: aquasecurity/trivy-action@master
              with:
                  scan-type: 'fs'
                  format:    'table'
                  severity:  'HIGH,CRITICAL'
                  exit-code: '1'
            - uses: github/codeql-action/init@v3
              with:
                  languages: javascript
            - uses: github/codeql-action/analyze@v3

// Enable Dependabot (renovate is also great):
// .github/dependabot.yml
version: 2
updates:
    - package-ecosystem: npm
      directory: /
      schedule: { interval: weekly }
      open-pull-requests-limit: 10
      groups:
          minor-patches:
              update-types: ['minor', 'patch']
    - package-ecosystem: github-actions
      directory: /
      schedule: { interval: weekly }
    - package-ecosystem: docker
      directory: /
      schedule: { interval: weekly }

// ─── STEP 4 — Triage SLAs ──────────────────────────────────────
// Without a target, scanners just generate noise.
//
//   • CRITICAL (CVSS 9+): patch within 7 days
//   • HIGH (7-8.9):       patch within 30 days
//   • MEDIUM (4-6.9):     next regular release
//   • LOW (<4):            tracked, no SLA
//
// Track findings in a real ticket system, not just a scanner dashboard.

// ─── STEP 5 — Lock-file hygiene ────────────────────────────────
// package.json says 'react: ^18.2.0'.
// package-lock.json pins the exact tree that was tested.
// Commit the lock file. Use 'npm ci' (not 'npm install') in CI.

npm ci          // installs from lockfile; fails if drift
yarn install --frozen-lockfile
pnpm install --frozen-lockfile
pip install -r requirements.lock --require-hashes
poetry install --no-update --sync

// ─── STEP 6 — Remove what you don't use ────────────────────────
npx depcheck                          // unused deps
npx knip                              // unused exports + deps + files
pip-extra-reqs                        // python

// ─── STEP 7 — Pin and verify ───────────────────────────────────
// GitHub Actions: pin to commit SHA, not tag (tags can move)
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11   # v4.1.1

// Docker: pin to digest
FROM node:20.10.0-alpine@sha256:abc123...

// npm: optionally enforce package-lock integrity
npm config set audit-signatures true     // verifies registry signatures

// ─── STEP 8 — Stay on supported branches ───────────────────────
// Node 16 went EOL in 2023; using it now means CVEs without patches.
// Track EOL: endoflife.date
//   node:    LTS only
//   python:  3.10+ (3.9 EOL Oct 2025)
//   ubuntu:  22.04 or 24.04 base images
//   alpine:  pin to a maintained release; rebuild monthly

// ─── STEP 9 — Runtime detection ────────────────────────────────
// SCA shows what you SHIPPED. Runtime shows what actually LOADS.
// Tools like Falco or eBPF-based runtime security catch loading of
// known-vulnerable libs even when SCA missed them.

// ─── STEP 10 — Incident playbook ───────────────────────────────
// When a new critical CVE drops in a transitive dependency at 5pm Friday:
//   1. Grep SBOMs across all services to find affected versions
//   2. Check exploitability: is the vulnerable code path reachable?
//   3. Patch or pin to a fixed version; rebuild + redeploy
//   4. If patch unavailable: WAF rule, kill switch, or feature-flag off
//   5. Postmortem: how did this slip past CI? tune severity threshold

// ─── CHECKLIST ─────────────────────────────────────────────────
// 1. SBOM generated per build, stored with the artifact
// 2. Scanner runs on every PR + nightly
// 3. Dependabot/Renovate open PRs continuously
// 4. Documented SLAs by severity
// 5. Lock files committed; CI uses --frozen-lockfile / npm ci
// 6. Actions/images pinned to digests or SHAs
// 7. Quarterly review of EOL runtimes and base images

Why it matters

A06 boils down to operational hygiene: generate SBOMs, scan in CI, patch on a documented SLA, pin actions and base images by digest. The vulnerabilities are almost always public — the gap is process, not knowledge.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// A06 Vulnerable / Outdated Components — Log4Shell, xz backdoor, leftPad…
// Fix: SBOM (SPDX / CycloneDX), dep scanners (Dependabot, Snyk, Trivy),
// patch SLAs.
Try it Yourself »

Discussion

Loading…