50 dependency supply chain review
Skill FluxonLab/Skillry/plugins/security/skills/50-dependency-supply-chain-review
Use when you need to review dependencies, scripts, lockfiles, package provenance, and install-time risks.From its SKILL.md
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.
SKILL.md
14.0 KB, ~3.3k tokens by cl100k_base, 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.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.