Supply Chain Security
Audit Workflow
Supply Chain Audit:
- [ ] Lockfile & integrity verification
- [ ] Install script review
- [ ] CI/CD pipeline security
- [ ] Package provenance & publishing
- [ ] Typosquatting & dependency confusion
- [ ] Secrets in CI/CD and artifacts
- [ ] Third-party script integrity (SRI)
Lockfile & Install Integrity
# Lockfile present and used
ls package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null
# CI should use frozen installs
rg -n "npm (ci|install)|yarn install|pnpm install" .github/ .gitlab-ci.yml 2>/dev/null
# Verify no scripts run unchecked in CI
rg -n "ignore-scripts" .github/ 2>/dev/null
Rules:
- Never
npm installin CI — usenpm ci - Pin Node.js version (
.nvmrc,enginesfield, CI matrix) - Enable
npm auditin CI pipeline - Consider
--ignore-scriptsuntil packages are vetted
Install Script Risks
High-risk lifecycle scripts: preinstall, install, postinstall, prepare
# Find packages with install scripts in your tree
node -e "
const {execSync}=require('child_process');
try {
const out=execSync('npm ls --all --parseable 2>/dev/null',{encoding:'utf8'});
// Manual review of node_modules/*/package.json scripts recommended
} catch(e) {}
"
rg -l "postinstall|preinstall" node_modules/*/package.json 2>/dev/null | head -20
| Risk Level | Indicator |
|---|---|
| Critical | Install script makes network requests to unknown domains |
| High | Install script accesses process.env for exfiltration |
| Medium | Native compilation (node-gyp) — expected for some packages |
| Low | prepare running build — common for TypeScript packages |
Typosquatting & Dependency Confusion
Check for:
- Package names similar to popular packages (e.g.,
lodashvslodahs) - Internal package names published publicly
- Scoped vs unscoped confusion (
@company/pkgvscompany-pkg)
# Review direct dependency names for typos
node -e "console.log(Object.keys({...require('./package.json').dependencies}))"
# Private registry config
rg -n "registry|@.*:registry" .npmrc .yarnrc.yml 2>/dev/null
Mitigations:
- Use scoped private packages (
@yourorg/package) - Configure
.npmrcwith scoped registry for internal packages - Enable npm provenance and trusted publishing
- Review new dependencies in PRs
CI/CD Pipeline Security
rg -n "secrets\.|GITHUB_TOKEN|NPM_TOKEN|password" .github/ .gitlab-ci.yml 2>/dev/null
rg -n "pull_request_target|workflow_run" .github/workflows/ 2>/dev/null
| Check | Requirement |
|---|---|
| Secrets scoped | Minimal permissions per workflow |
| PR workflows | No secret access on untrusted forks |
pull_request_target |
Never checkout untrusted code with secrets |
| Action pinning | Pin to SHA, not @v1 tags |
| Artifact signing | Sign releases, verify in deployment |
| OIDC | Use OIDC for cloud deploys (no long-lived keys) |
GitHub Actions Hardening
permissions:
contents: read
# Pin actions to commit SHA
- uses: actions/checkout@<sha> # not @v4
npm Provenance & Publishing
For projects that publish packages:
- Enable npm provenance
- Use 2FA on npm account (publish + authorize)
- Use trusted publishers (GitHub OIDC)
- Never share npm tokens — use CI OIDC
SBOM (Software Bill of Materials)
# Generate SBOM
npx --yes @cyclonedx/cyclonedx-npm --output-file sbom.json 2>/dev/null
# or
npx --yes @anchore/syft packages dir:. -o cyclonedx-json 2>/dev/null
Include SBOM in releases for enterprise consumers.
Third-Party Scripts (Frontend)
rg -n "<script.*src=" --glob "*.{html,jsx,tsx,vue,svelte}"
rg -n "integrity=" --glob "*.{html,jsx,tsx}"
Rules:
- Subresource Integrity (SRI) on all CDN scripts
- Allowlist CDN domains in CSP
script-src - Self-host critical libraries when possible
- Monitor CDN compromises
Environment & Artifact Leaks
# Secrets in build output
rg -n "API_KEY|SECRET|PASSWORD|PRIVATE" dist/ .next/ build/ 2>/dev/null
# .env in Docker images
rg -n "COPY.*\.env|ADD.*\.env" Dockerfile* 2>/dev/null
Report Template
## Supply Chain Security Assessment
### Lockfile & Install
- [status] Lockfile committed and CI uses frozen install
- [status] Install scripts reviewed
### CI/CD
- [status] Actions pinned to SHA
- [status] Minimal workflow permissions
- [finding] PR workflow exposes secrets — details
### Dependencies
- [finding] Package X has suspicious postinstall script
- [finding] Unscoped internal package name collision risk
### Recommendations
1. Add `npm ci --ignore-scripts` to CI, allowlist safe scripts
2. Pin GitHub Actions to commit SHAs
3. Enable npm provenance for published packages
Incident Response
If a compromised package is detected:
- Stop — remove package, block in
.npmrc - Assess — check logs for exfiltration, rotate all secrets
- Notify — security team, affected users
- Remediate — clean install from lockfile, audit git history
- Prevent — add package to deny list, improve review process