Security No. 290

Supply Chain Audit skill for Claude Code

Triage every CVE instead of just counting them. Instead of running npm audit fix --force and hoping, Claude scans each ecosystem, checks whether each vulnerable package is actually in the runtime and reachable, and sorts findings into fix now, planned, or accepted with reasons. It also catches the quieter risks: missing lockfiles, install scripts, dependency confusion, typosquats, and GitHub Actions pinned to mutable tags.

  • namesupply-chain-audit
  • size182 lines · ≈2,100 tokens
  • files1
  • licenseMIT
  • updated

What Claude sees before loading it

This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.

description: Audits third-party dependencies and build inputs for risk — known vulnerabilities with npm audit, pip-audit, osv-scanner, and govulncheck, reachability triage, lockfile integrity, install-script exposure, typosquatting and abandoned packages, pinned CI actions, provenance and SBOMs — and produces a prioritized remediation plan. Use when asked to audit dependencies, fix npm audit or Dependabot alerts, vet a new package, respond to a compromised package advisory, or harden the build pipeline.

Try asking

  • We have 47 npm audit warnings — which ones actually matter?
  • Vet this package before I add it: is it safe and maintained?
  • Harden our CI so a compromised dependency or action can't steal secrets

Use it when

  • Dependabot, npm audit, or pip-audit reports are piling up
  • A widely used package was reported compromised or malicious
  • Evaluating a new third-party dependency before adding it
  • Preparing an SBOM or a dependency section for a security review

Skip it when

How to check the result

Re-running every scanner leaves only findings documented as planned or accepted with reasons, tests pass after updates, and CI fails on new high-severity advisories.

The common mistake it prevents

Running npm audit fix --force across the tree, which silently applies breaking major upgrades while the one reachable vulnerability may still be pinned by a transitive parent.

~/.claude/skills/supply-chain-audit/SKILL.md

--- name: supply-chain-audit description: Audits third-party dependencies and build inputs for risk — known vulnerabilities with npm audit, pip-audit, osv-scanner, and govulncheck,… license: MIT ---

Done well means: every known vulnerability is triaged as fix, mitigate, or accept with a reason (not just counted); lockfiles are committed and enforced; new packages are vetted before install; install-time code execution is limited; CI uses pinned, verified inputs; and there is an SBOM you can query when the next advisory lands.

Hard rules

  • Do not run npm audit fix --force or bulk major upgrades without the user’s approval; they change behavior. Propose them as separate, tested changes.
  • Never install a package you are vetting into the user’s main environment “to check it”. Inspect metadata and source first; use a throwaway container if execution is needed.
  • A CVE count is not a risk assessment. Triage reachability and exposure.
  • On a compromised-package advisory, treat any machine that installed the bad version as potentially compromised (install scripts run with the user’s privileges): rotate credentials that were on it.

Workflow

- [ ] 1. Inventory ecosystems, manifests, lockfiles, and CI install steps
- [ ] 2. Run vulnerability scanners per ecosystem
- [ ] 3. Triage each finding: reachable? exposed? fix available?
- [ ] 4. Check lockfile and install hygiene
- [ ] 5. Check package health: typosquats, abandonment, install scripts
- [ ] 6. Check CI/CD inputs: actions, images, curl-pipe-sh
- [ ] 7. Generate an SBOM; write the remediation plan

1. Inventory

find . -name node_modules -prune -o \( -name package.json -o -name package-lock.json -o -name pnpm-lock.yaml -o -name yarn.lock -o -name requirements*.txt -o -name pyproject.toml -o -name uv.lock -o -name poetry.lock -o -name go.mod -o -name Cargo.lock -o -name Gemfile.lock -o -name composer.lock \) -print

Flag immediately: a manifest without a lockfile; multiple lockfiles for one package manager; CI running npm install instead of npm ci.

2. Scan

EcosystemCommand
npmnpm audit --omit=dev (production), npm audit --json > audit.json
pnpmpnpm audit --prod
Yarn Berryyarn npm audit --all --recursive
Pythonpip-audit -r requirements.txt or pip-audit inside the project venv; uv projects: export first with uv export --format requirements-txt > req.txt
Gogovulncheck ./... (call-graph reachability built in)
Rustcargo audit
Rubybundle exec bundler-audit check --update
Any / polyglotosv-scanner scan source -r . (OSV database, reads lockfiles)
Container imagestrivy image <ref> (see container-security)

Run the dev-dependency scan too, but rank it lower unless dev tools run in CI with secrets or ship in artifacts.

3. Triage

For each finding, answer and record:

QuestionHow to answer
Is the vulnerable package in the production runtime?npm ls <pkg> / pnpm why <pkg> / pip show + pipdeptree -r -p <pkg> / go mod why <mod>
Is the vulnerable function reachable?govulncheck reports this; elsewhere read the advisory’s affected function and grep for its use
Is it exposed to attacker input?E.g. a ReDoS in a CLI arg parser used only at build time is low; in a request parser it is high
Is a fixed version available?Advisory “patched versions”; npm view <pkg> versions
Is the fix semver-compatible?Patch/minor: apply now. Major: plan with tests

Decision:

  • Fixed version within range → update the lockfile (npm update <pkg>, pnpm update <pkg>, uv lock --upgrade-package <pkg>), run tests.

  • Fix only in a transitive dep the parent pins → override, then file upstream:

    // package.json (npm)
    { "overrides": { "vulnerable-pkg": "^2.4.1" } }
    // pnpm: "pnpm": { "overrides": { "vulnerable-pkg": "^2.4.1" } }
    // yarn: "resolutions": { "vulnerable-pkg": "^2.4.1" }
  • No fix and reachable → mitigate (input validation, disable feature, WAF rule) or replace the package. Document it.

  • Not reachable / not in runtime → accept with a written reason and a review date; use the scanner’s ignore file so it stays visible (.nsprc/audit-ci allowlist, pip-audit --ignore-vuln ID, osv-scanner.toml [[IgnoredVulns]] with reason).

4. Lockfile and install hygiene

  • Lockfiles committed for apps; CI uses frozen installs: npm ci, pnpm install --frozen-lockfile, yarn install --immutable, uv sync --locked, pip install --require-hashes -r requirements.txt (generate hashes with uv pip compile --generate-hashes or pip-compile --generate-hashes).
  • Review lockfile diffs in PRs: new resolved hosts that are not your registry, or integrity hash changes without a version change, are red flags.
  • Private package names: register or scope them (@org/) so a public package with the same name cannot win (dependency confusion). Set registry/@org:registry in .npmrc, and use --index-url not --extra-index-url for private Python indexes.
  • Install scripts: npm runs preinstall/postinstall for every dependency. pnpm 10 does not run dependency lifecycle scripts unless allowlisted (onlyBuiltDependencies). For npm in CI, consider npm ci --ignore-scripts plus an explicit rebuild of packages that need native builds.
  • Release-age delay: hold back versions published in the last few days (most malicious versions are yanked within hours). pnpm supports minimumReleaseAge; uv supports exclude-newer; Renovate supports minimumReleaseAge. Check your tool version.

5. Package health and vetting a new dependency

Before adding a package, check:

- [ ] Exact name matches the intended project (typosquats: lodahs, reqeusts, python-dateutils)
- [ ] Repository link exists, matches the package, and has recent maintained activity
- [ ] Weekly downloads / dependents plausible for its claimed popularity
- [ ] Maintainers: count, recent ownership changes (a red flag before a malicious release)
- [ ] Install scripts present? Read them
- [ ] Transitive dependency count reasonable for what it does
- [ ] License compatible
- [ ] Could 20 lines of our own code replace it?
npm view <pkg> name version repository.url maintainers time.modified scripts
npm pack <pkg> --dry-run          # lists files without installing
pip download <pkg> --no-deps -d /tmp/inspect && ls /tmp/inspect   # inspect wheel/sdist

OpenSSF Scorecard (scorecard --repo=github.com/org/project) and deps.dev give quick signal on maintenance and security practices.

6. CI/CD inputs

  • Pin third-party GitHub Actions to a full commit SHA with a version comment: uses: some-org/some-action@8f4b7f84864484a7bf31766abe9204da3cbe65b3 # v4.1.0. Tags are mutable; a compromised tag runs in every workflow. Dependabot can update SHAs.
  • Set permissions: to least privilege at workflow level (contents: read default).
  • Never pull_request_target with checkout of the PR head and secrets available.
  • Base images pinned by digest for release builds; no curl ... | sh without checksum verification.

7. Provenance, SBOM, and plan

  • npm: npm audit signatures verifies registry signatures and provenance attestations for installed packages. Publish your own with npm publish --provenance from CI.
  • Containers/artifacts: sign with Sigstore cosign; verify in deploy.
  • SBOM: syft dir:. -o cyclonedx-json > sbom.json (or syft <image>), stored per release so you can answer “are we affected?” in minutes.

Output template

# Dependency audit: <repo> @ <commit> (<date>)

| Severity | Found | Fixed now | Planned | Accepted |
|---|---|---|---|---|

## Fix now (reachable, fix available)
| Package | Installed -> Fixed | Advisory | Path | Action |
|---|---|---|---|---|
| axios | 1.6.0 -> 1.12.0 | GHSA-xxxx | direct | `npm i axios@^1.12.0`, tests pass |

## Planned (major upgrade or no fix)
## Accepted (not reachable / dev-only) — with reason and review date
## Hygiene findings
- CI uses `npm install` (should be `npm ci`)
- 3 third-party actions pinned by tag, not SHA
## Recommendations

Verification

  • Re-run every scanner after changes; remaining findings all appear in the Accepted or Planned sections with reasons.
  • Full test suite and build pass after updates; lockfile diff contains only intended changes.
  • CI fails on new high/critical findings (e.g. npm audit --omit=dev --audit-level=high exits non-zero) so regressions are caught.

About this skill

Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.

esc