50 dependency supply chain review
Skill FluxonLab/Skillry/plugins/security/skills/50-dependency-supply-chain-review
Installable, permission-bounded, multi-platform agent skills & subagents for Claude Code, Codex, Copilot & Gemini/Antigravity — 125 skills + 73 subagents across 18 departments, with a validation harness, native plugin marketplace, and full upstream attribution. by FluxonLab.
npx -y skills add FluxonLab/Skillry --skill 50-dependency-supply-chain-reviewAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when you need to review dependencies, scripts, lockfiles, package provenance, and install-time risks.
SKILL.md
14.0 KB, as published. Nobody here has run it
Dependency Supply Chain Review
Purpose
Audit the project's package dependency graph for known CVEs, suspicious install-time scripts, lockfile integrity issues, typosquatting candidates, outdated packages with breaking changes, and transitive dependency risks. Every finding gets a severity, a concrete package reference, and a prioritized remediation step. The audit is read-only and non-destructive — no packages are installed, upgraded, or removed without explicit user approval.
A dependency review that only runs npm audit and lists the output is not sufficient. The goal is to assess exploitability in context (a server-side RCE in a browser-only bundle is different from one in a server process), to check install-time code execution, to verify lockfile integrity, and to identify structural supply-chain risks such as namespace confusion or unreviewed postinstall scripts.
When to use
npm audit,yarn audit, orpip-audithas flagged vulnerabilities and you need a structured remediation plan.- A PR adds or upgrades packages and you want to verify supply-chain safety before merge.
- The project has not had a dependency review in more than 90 days.
- A postinstall or prepare script in a dependency is executing code at install time.
- The lockfile (
package-lock.json,yarn.lock,poetry.lock,pnpm-lock.yaml) is missing or was recently deleted and regenerated. - A security incident or CVE disclosure has named a package in the project's dependency tree.
When not to use
- The project has no third-party dependencies (single-file scripts, standard-library only).
- You need to audit application runtime logic unrelated to packages.
- A dedicated security scanning tool (Snyk, Dependabot, Socket) has already triaged all findings and the task is to implement fixes — use a code-editing skill instead.
Procedure
-
Confirm lockfile presence and integrity. Check that
package-lock.json/yarn.lock/pnpm-lock.yaml/poetry.lockexists and is committed. A missing lockfile means installs are non-deterministic. Verify the lockfile was generated by the matching tool and version (checklockfileVersioninpackage-lock.json— v3 for npm 7+). -
Run the audit non-destructively. Execute
npm audit --jsonoryarn audit --jsonand capture the output to a temp file. Do not runnpm audit fix --forcewithout reviewing the proposed changes. For Python, runpip-audit --format json. For Go, rungovulncheck ./.... -
Classify each CVE by exploitability in this project. For every finding, determine:
- Severity (critical/high/moderate/low) as reported by the registry.
- Is the vulnerable code path reachable in this project? A server-side RCE in a package only imported in a browser bundle that never runs on the server is unexploitable in that context.
- Is a non-breaking fix version available? Record whether the fix is a patch, minor, or major bump.
-
Inspect install-time scripts. For every dependency with
postinstall,prepare,preinstall, orinstallscripts in itspackage.json, read what the script does. Flag any that download binaries, executecurl/wget, modify system files, or phone home. Legitimate packages likeesbuildandpuppeteerdownload platform-specific binaries — verify the download uses a checksum. -
Check for typosquatting candidates. Compare recently added package names against their intended counterparts:
lodashvsl0dash,expressvsexpres. Pay special attention to packages added in the last PR with few public downloads or a short publish history. Use the npm registry API to check download counts and creation dates. -
Audit transitive dependency pinning. For CVEs in transitive (indirect) dependencies where a direct upgrade cannot resolve the issue, check whether
overrides(npm 8+) orresolutions(yarn) can pin the safe transitive version. Document which CVEs are unresolvable without a major dependency change. -
Verify CI uses a reproducible install command.
npm cifails when the lockfile is out of sync withpackage.json, ensuring reproducibility.npm installsilently updates the lockfile. CI pipelines must usenpm ci(oryarn install --frozen-lockfile/pnpm install --frozen-lockfile). -
Check for outdated major versions. Run
npm outdatedand flag packages more than one major version behind, especially those with known end-of-life status (e.g., a runtime version past its LTS window, a framework version with no security patches). -
Review private registry configuration. If
.npmrcconfigures a private registry scope, confirm it is scoped to the organization's namespace (e.g.,@company/*) and does not redirect all traffic through an untrusted registry. Unscoped private registry config enables dependency confusion attacks where a public package with the same name and a higher version takes precedence. -
Document approved exceptions. For CVEs assessed as not exploitable in context, create or update an audit exception file (e.g.,
npm-audit-exceptions.jsonor.auditignore) with the CVE ID, the package, the reason for the exception, the reviewer's name, and the review date.
Concrete checks
- Lockfile present, committed, and matches the package manager version (check
lockfileVersionfield). -
npm audit(or equivalent) returns zero critical or high findings, or all findings have documented exceptions with justification. - No postinstall scripts download remote code, execute
curl/wget, or modify paths outside the package directory. - No package names match known typosquatting patterns (one character off from a popular package).
- Vulnerable transitive deps are addressed via
overrides/resolutionswhere a direct upgrade cannot fix them. - CI pipeline uses
npm ci/--frozen-lockfile/--immutable, notnpm install. -
.npmrcscopes any private registry to@org-scope/*only; no full-redirect to an untrusted registry. - All packages with known EOL runtime or framework status have a documented upgrade timeline.
-
package.jsondependenciesranges are not*or>=0.0.0for production packages. - Audit exceptions file exists with CVE ID, package, reason, reviewer, and date for each waived finding.
-
devDependenciesare notrequire()-d in application code that ships to production.
Commands
# Detect package manager from lockfile
ls package-lock.json 2>/dev/null && echo "npm" || true
ls pnpm-lock.yaml 2>/dev/null && echo "pnpm" || true
ls yarn.lock 2>/dev/null && echo "yarn" || true
ls bun.lockb 2>/dev/null && echo "bun" || true
ls poetry.lock 2>/dev/null && echo "poetry (python)" || true
# Non-destructive npm audit (capture JSON; do NOT run fix yet)
npm audit --json > /tmp/npm-audit.json 2>&1
cat /tmp/npm-audit.json | python3 -c "import json,sys; d=json.load(sys.stdin); print('critical:', d.get('metadata',{}).get('vulnerabilities',{}).get('critical',0), 'high:', d.get('metadata',{}).get('vulnerabilities',{}).get('high',0))"
# Python / pip
pip-audit --format json --output /tmp/pip-audit.json 2>/dev/null || echo "pip-audit not installed"
# Go
govulncheck ./... 2>/dev/null || echo "govulncheck not installed"
# Check lockfile version
node -e "const l=require('./package-lock.json'); console.log('lockfileVersion:', l.lockfileVersion)"
# Inspect all postinstall / prepare scripts in direct dependencies
node -e "
const pkg = require('./package.json');
const deps = {...(pkg.dependencies||{}), ...(pkg.devDependencies||{})};
Object.keys(deps).forEach(name => {
try {
const p = require('./node_modules/' + name + '/package.json');
const s = p.scripts || {};
const hooks = ['postinstall','preinstall','install','prepare'].filter(k => s[k]);
if (hooks.length) console.log(name + '@' + p.version + ':', hooks.map(k => k + '=' + s[k]).join(' | '));
} catch(e) {}
});
"
# Check for outdated packages (read-only)
npm outdated 2>/dev/null || true
# Check private registry config
cat .npmrc 2>/dev/null | grep -E "registry|scope" || echo "no .npmrc"
# Check whether CI uses npm ci or npm install
rg -n "npm install\b" .github/workflows/ .gitlab-ci.yml Makefile 2>/dev/null || true
rg -n "npm ci\b" .github/workflows/ .gitlab-ci.yml Makefile 2>/dev/null || true
# Check for wildcard or loose version ranges in production deps
node -e "
const pkg = require('./package.json');
Object.entries(pkg.dependencies||{}).forEach(([k,v]) => {
if (v === '*' || v.startsWith('>=0') || v.startsWith('x')) console.log('LOOSE RANGE:', k, v);
});
"
# Check devDependencies used in production code (node_modules audit)
# List devDep names, then grep for require/import of those names in src/
node -e "const p=require('./package.json'); Object.keys(p.devDependencies||{}).slice(0,20).forEach(n=>console.log(n))" \
| xargs -I{} sh -c 'rg -l "require.*{}\|from.*{}" src/ 2>/dev/null && echo "DEV IN PROD: {}" || true'
# Typosquatting quick check: compare package names against npm registry
# (manual step — check these with: npm view <suspected-package> time --json | head -5)
# Look for: very recent creation, <1000 weekly downloads, owner with no other packages
# Transitive CVE: identify the dependency chain for a specific package
npm ls <vulnerable-package> 2>/dev/null | head -20
# Check overrides/resolutions in package.json
node -e "const p=require('./package.json'); console.log(JSON.stringify(p.overrides||p.resolutions||{}, null,2))"
# Verify the lockfile is what was actually installed (hash check)
npm ci --dry-run 2>/dev/null | tail -5 || echo "dry-run not supported; run npm ci in CI only"
Severity rubric
| Severity | Example |
|---|---|
| Critical | Remotely exploitable CVE (RCE, SQL injection) in a package reachable from a production request handler. Postinstall script downloads and executes arbitrary code. Confirmed typosquatting package installed. |
| High | XSS or path traversal CVE in a package handling untrusted user input. Lockfile deleted and regenerated without audit of version changes. npm install (not npm ci) used in CI, allowing lockfile drift. |
| Medium | ReDoS or DoS CVE in a package reachable from user input. Loose production version range (^1.0.0 is fine; >=1 <99 is not). devDependency found in production code. Outdated major version with known vulnerabilities in that major. |
| Low | Informational CVE not reachable in this project's code paths, with a documented exception. Outdated minor version with no known vulnerability. Missing audit exception documentation for a known, assessed CVE. |
Common issues & anti-patterns
- Deleted and regenerated lockfile: dependency versions silently drift; every transitive version must be re-reviewed as if all packages were newly added.
npm installin CI: the lockfile can mutate between CI runs; always usenpm ci. A failingnpm ciis not a problem to paper over — it signals a real inconsistency betweenpackage.jsonand the lockfile.- Unpinned
devDependenciespromoted to production: arequire()in application code that pulls a dev-only package will silently fail in a production Docker image built fromnpm ci --omit=dev. --legacy-peer-depsflag in CI: this flag silently installs incorrect peer versions. Its presence signals an outdated dependency graph that needs resolution, not suppression.- Scoped package namespace confusion: if your org namespace
@acmeis not claimed on the public registry, an attacker can publish@acme/internal-libpublicly with a higher version and npm will prefer it (dependency confusion attack). - Binary download postinstall without checksum verification:
puppeteer,cypress,esbuild, and similar packages download platform binaries at install time. Verify the download script checks a hash against a bundled manifest — unchecked binary downloads are a supply chain risk. - Audit false negatives from bundling:
npm auditinspectsnode_modules, but if a vulnerable package is bundled into a client-side chunk via webpack/rollup and then dropped fromnode_modules(e.g., via tree-shaking), audit may not flag it. Check the final bundle's included packages separately. - Exception file without dates: a "not exploitable" exception from 18 months ago may no longer be valid if the package's usage has changed. All exceptions must have a review date and a re-review interval.
Required output
## Dependency Supply Chain Review
### Critical CVEs requiring immediate fix
| Package | Installed | Safe version | CVE | Exploitable in this project |
|---------|-----------|-------------|-----|----------------------------|
### High CVEs — fix before next release
| Package | Installed | Safe version | CVE | Notes |
### Suspicious install-time scripts
- package@version: script content summary, risk level, recommendation.
### Outdated packages (1+ major behind)
| Package | Current | Latest | EOL? | Upgrade priority |
|---------|---------|--------|------|-----------------|
### Lockfile status
- Present: yes/no. Generator: npm/yarn/pnpm. Version: X. CI uses reproducible install: yes/no.
### Private registry config
- .npmrc present: yes/no. Scoped to org namespace only: yes/no. Risk: none/low/high.
### Audit exceptions (assessed not exploitable)
| CVE | Package | Reason | Reviewer | Date |
### Recommended next commands
1. npm audit fix # review diff before committing — run npm audit again after to confirm
2. ...
### Summary
- Total direct dependencies: N. Total audit findings: N (critical: N, high: N).
- Single highest-priority action: one sentence.
Safety
- Run
npm audit --json(read-only) only. Do not runnpm audit fix --force,npm install, or any script that modifiesnode_modulesor the lockfile without explicit user approval. - Do not print package registry tokens or
.npmrcauth values. - Do not run postinstall scripts or execute any downloaded binary as part of the review.
- Do not approve or merge a PR that adds a package with an unreviewed postinstall script — surface it as a finding first.