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.
- name
supply-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
- You are doing routine version bumps with no security driver — use dependency-upgrades instead
- The concern is OS packages inside container images — use container-security instead
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.
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 --forceor 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
| Ecosystem | Command |
|---|---|
| npm | npm audit --omit=dev (production), npm audit --json > audit.json |
| pnpm | pnpm audit --prod |
| Yarn Berry | yarn npm audit --all --recursive |
| Python | pip-audit -r requirements.txt or pip-audit inside the project venv; uv projects: export first with uv export --format requirements-txt > req.txt |
| Go | govulncheck ./... (call-graph reachability built in) |
| Rust | cargo audit |
| Ruby | bundle exec bundler-audit check --update |
| Any / polyglot | osv-scanner scan source -r . (OSV database, reads lockfiles) |
| Container images | trivy 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:
| Question | How 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]]withreason).
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 withuv pip compile --generate-hashesorpip-compile --generate-hashes). - Review lockfile diffs in PRs: new
resolvedhosts 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). Setregistry/@org:registryin.npmrc, and use--index-urlnot--extra-index-urlfor private Python indexes. - Install scripts: npm runs
preinstall/postinstallfor every dependency. pnpm 10 does not run dependency lifecycle scripts unless allowlisted (onlyBuiltDependencies). For npm in CI, considernpm ci --ignore-scriptsplus 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 supportsexclude-newer; Renovate supportsminimumReleaseAge. 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: readdefault). - Never
pull_request_targetwith checkout of the PR head and secrets available. - Base images pinned by digest for release builds; no
curl ... | shwithout checksum verification.
7. Provenance, SBOM, and plan
- npm:
npm audit signaturesverifies registry signatures and provenance attestations for installed packages. Publish your own withnpm publish --provenancefrom CI. - Containers/artifacts: sign with Sigstore
cosign; verify in deploy. - SBOM:
syft dir:. -o cyclonedx-json > sbom.json(orsyft <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=highexits 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.