When to Use
- Use when: preparing a compliance report or audit requiring SBOM
- Use when: a dependency was flagged in a CVE after a recent update
- Use when: setting up a new service and locking down its dependency policy
- Use when: responding to a supply chain incident (e.g., compromised npm package)
- Do NOT use for: SAST / code vulnerability scanning — see security-pipeline
- Do NOT use for: secrets in CI — see secret-management
SBOM Generation
# Syft — generates SBOM in multiple formats
# Install: brew install syft or docker pull anchore/syft
# From source directory
syft dir:. -o spdx-json > sbom.spdx.json
syft dir:. -o cyclonedx-json > sbom.cyclonedx.json
# From container image
syft myrepo/api:latest -o spdx-json > image-sbom.spdx.json
# Attach SBOM to GitHub release
gh release upload v1.2.3 sbom.spdx.json
# CI — generate and attest SBOM on every release
- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
artifact-name: sbom.spdx.json
output-file: sbom.spdx.json
- name: Attest SBOM (Sigstore)
uses: actions/attest-sbom@v1
with:
subject-path: dist/
sbom-path: sbom.spdx.json
Dependency Provenance (npm)
# Check npm provenance — verifies package was built from declared source
npm install --dry-run 2>&1
npm audit signatures # verify signatures on all installed packages
# View provenance for a specific package
npm view react dist-tags
npm view react@18.3.0 _id dist.integrity dist.signatures
// package.json — enable provenance-required policy (npm v9.5+)
{
"scripts": {
"install:verified": "npm ci --audit-level=high"
}
}
Lockfile Integrity
# Never skip lockfile — reproducible installs
npm ci # uses package-lock.json exactly — errors if drift
pnpm install --frozen-lockfile # same for pnpm
# ❌ npm install in CI — can update lockfile silently
# ✅ npm ci in CI — fails if lockfile is out of date
# Detect lockfile tampering (before install in sensitive environments)
git diff HEAD package-lock.json # check if lockfile changed unexpectedly
Typosquatting Detection
# Common attack patterns:
# lodash → 1odash (digit not letter)
# moment → momment (double letter)
# express → expres (missing letter)
# axios → axio (missing trailing s)
# Check for suspicious similar names
pip install safety # Python equivalent CVE + name check
npx package-name-check axios # checks for known typosquats
# Verify publisher before adding new packages
npm info <package> | grep -E "maintainers|author|homepage"
# Expect: well-known maintainer, GitHub link, published date makes sense
Dependency Confusion Attack Prevention
Attack: attacker publishes a public package with same name as your
internal private package — CI picks up the public version.
Fix: scope all internal packages (@myorg/utils, not just utils)
Pin private registry in .npmrc:
# .npmrc — force internal packages to private registry
@myorg:registry=https://npm.myorg.com
//npm.myorg.com/:_authToken=${NPM_PRIVATE_TOKEN}
# For all other packages, use public registry
registry=https://registry.npmjs.org
Artifact Signing (SLSA Level 2+)
# GitHub Actions — sign release artifacts with Sigstore cosign
- name: Sign artifact
uses: sigstore/cosign-action@v3
with:
sign: ./dist/myapp-linux-amd64
# Verify signature before deployment
- name: Verify artifact
run: |
cosign verify-blob \
--certificate-identity-regexp "https://github.com/myorg/myrepo/.github/workflows/release.yml" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
--bundle dist/myapp-linux-amd64.bundle \
dist/myapp-linux-amd64
Dependency Update Policy
# .github/dependabot.yml — automated PRs for updates
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule: { interval: weekly }
groups:
dev-deps:
patterns: ["eslint*", "typescript", "vitest"]
ignore:
- dependency-name: "some-frozen-dep"
versions: [">= 3.0.0"] # breaking change, intentionally pinned
open-pull-requests-limit: 10
Anti-Fake-Pass Rules
Before claiming supply chain security is in place, you MUST show:
- SBOM generated and attached to every release artifact
-
npm ci/pnpm install --frozen-lockfileused in CI — notnpm install - Internal packages scoped (
@myorg/) — dependency confusion prevented -
npm audit/pip-auditruns in CI with--audit-level=highexit code - New dependencies verified: publisher identity, repo link, published date checked
- Dependabot or Renovate configured — no manual-only dependency updates
Reference: gates/anti-fake-pass-gate.md