| name | npm-pr-review-npm-supply-chain |
|---|---|
| description | Reviews pull requests for npm supply chain security risks. Use this skill whenever a user asks you to review a PR, check a diff, audit dependency changes, or evaluate whether it's safe to merge — especially when package.json, package-lock.json, or node_modules are involved. Also trigger for questions like "is this PR safe?", "what changed in dependencies?", or "should I approve this?". Even if the PR is about something else, if it touches npm files, run this review. The goal is to catch supply chain attacks, compromised packages, and dangerous postinstall hooks before they reach production. |
You are reviewing a pull request with the lens of npm supply chain security. Even if the PR seems routine, dependency changes are a common vector for sophisticated attacks — including ones where the malicious code runs at install time and self-destructs, leaving no trace.
Your job is to produce a structured security report the author can act on.
The user may paste a diff directly, share a GitHub URL, or describe the changes. If they give you a URL, use web_fetch to retrieve it. If the diff isn't available, ask for it — you need to see the actual changes to package.json and package-lock.json at minimum.
Work through each category below. Not every category will be relevant to every PR — skip ones where there's genuinely nothing to flag, but be thorough where there is.
For every new or changed package in package.json or package-lock.json:
- Is this package expected? Does it appear anywhere in the source code (imports, requires)? A package listed as a dependency but never imported anywhere is a strong red flag — this is exactly how
plain-crypto-jswas smuggled into the axios attack. - Is the version recently published? Brand-new package versions (published within the last 24–48 hours) carry elevated risk — malicious packages are typically identified within that window. Note if a new version was published very recently relative to the PR.
- Does the package name look suspicious? Watch for typosquatting (e.g.,
axois,lodahs), name-squatting on legitimate packages with slight variations (e.g.,plain-crypto-jsmimickingcrypto-js), or packages that clone a real package's description and homepage. - Is the publisher trustworthy? If you can check, does the package have a publishing history, maintainer reputation, and GitHub presence that matches its claimed identity?
- Does the version have a corresponding git tag? Legitimate releases of well-maintained packages usually have a matching tag and commit in the source repo. A version that exists only on npm but has no corresponding GitHub release is suspicious.
This is critical. Check both package.json (the project's own) and any dependency manifests visible in the diff.
- Does any package introduce or modify a
postinstall,preinstall,install, orpreparescript? - Is that script doing something legitimate (e.g., compiling native code), or is it opaque/obfuscated?
- Does the project use
--ignore-scriptsin CI? If not, flag this as a hardening recommendation.
Postinstall hooks run automatically on npm install with no user prompt, and self-deleting malware can execute entirely before npm finishes — leaving no forensic trace.
- Is
package-lock.jsonoryarn.lockincluded in the PR alongsidepackage.jsonchanges? If dependencies changed but the lockfile didn't, that's a problem. - Do the versions in the lockfile match what's declared in
package.json? Mismatches can allow resolution to an unexpected (potentially malicious) version. - Are there unexplained additions to the lockfile — packages that weren't in
package.jsonbut appeared as transitive dependencies? New transitive dependencies are worth calling out.
- Does the project use npm's OIDC Trusted Publishers or GitHub Actions for publishing? If a new version bypasses that (e.g., published manually with a token), flag it.
- Are there changes to CI/CD pipeline files (
.github/workflows/,.circleci/, etc.) that alter hownpm installor publishing runs? - Is
npm ciused instead ofnpm installin automated workflows?npm ciis strictly reproducible;npm installcan silently upgrade.
Think about what secrets are available in the environment where npm install runs. If a postinstall hook ran malicious code, what could it access?
- Environment variables (cloud credentials, API keys, tokens)
.envfiles in the project root- SSH keys and git credentials
- CI/CD secrets injected into the runner environment
Flag if the PR increases this surface (e.g., running installs with elevated permissions, or in a context with more secrets than necessary).
- Does the project's CI/CD environment have network egress restrictions? Malware in postinstall hooks phones home to a C2 server — if all outbound traffic is allowlisted, this fails silently.
- If there's no egress control, flag it as a hardening recommendation.
Always produce a report with this structure:
## npm Supply Chain Security Review
### Summary
[1–3 sentences: overall risk level (Low / Medium / High / Critical) and the key reason]
### Findings
#### 🔴 Critical / 🟠 High / 🟡 Medium / 🟢 Low
[One section per finding, with:
- What you observed
- Why it matters
- What to do about it]
### What looks good
[Brief list of things that are done right — lockfile present, ignore-scripts used, etc.]
### Hardening recommendations
[Things not flagged as findings but worth improving — even if this PR is clean]
If there are no findings at a severity level, omit that level's section rather than writing "None."
- Be specific. Name the exact package, version, and file where you spotted something.
- Distinguish between "this is definitely suspicious" and "this is worth verifying manually."
- Don't cry wolf — if a package addition is well-known, widely used, and the version has a long history, say so clearly.
- If you can't access registry metadata (no web search), say so and advise the user to check manually via
npm view <package> timeor the npm registry web UI. - When in doubt, recommend
--ignore-scriptsand lockfile pinning — these are low-cost and high-value controls regardless of any specific finding.
- Package in
package.jsondependencies but never imported in source code postinstallscript that is obfuscated, callscurl,wget,python, or writes to temp directories- Version published within the last 24 hours
- Package name that closely resembles a popular package but differs slightly
package.jsonchanged without a corresponding lockfile update- Manual publish (no OIDC / GitHub Actions link) for a package that normally uses automated publishing
- Version exists on npm but has no matching git tag or commit
- Removal of a
prepareorhuskyscript alongside other changes (may indicate bypass of pre-commit checks) - New transitive dependency that doesn't appear to be pulled in by anything