Skip to content

Instantly share code, notes, and snippets.

@nym
Created March 31, 2026 14:01
Show Gist options
  • Select an option

  • Save nym/bf2c2e755ecb92bac2cf202053b38f30 to your computer and use it in GitHub Desktop.

Select an option

Save nym/bf2c2e755ecb92bac2cf202053b38f30 to your computer and use it in GitHub Desktop.
A skill for auditing PRs for potentially compromising issues around supply chain attacks
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.

npm Supply Chain PR Review

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.


How to get the PR content

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.


What to check

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.

1. Dependency additions and upgrades

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-js was 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-js mimicking crypto-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.

2. postinstall and lifecycle scripts

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, or prepare script?
  • Is that script doing something legitimate (e.g., compiling native code), or is it opaque/obfuscated?
  • Does the project use --ignore-scripts in 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.

3. Lockfile integrity

  • Is package-lock.json or yarn.lock included in the PR alongside package.json changes? 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.json but appeared as transitive dependencies? New transitive dependencies are worth calling out.

4. Publishing and CI/CD pipeline signals

  • 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 how npm install or publishing runs?
  • Is npm ci used instead of npm install in automated workflows? npm ci is strictly reproducible; npm install can silently upgrade.

5. Secret exposure surface

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)
  • .env files 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).

6. Egress controls

  • 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.

Report format

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."


Tone and calibration

  • 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> time or the npm registry web UI.
  • When in doubt, recommend --ignore-scripts and lockfile pinning — these are low-cost and high-value controls regardless of any specific finding.

Quick reference: red flags at a glance

  • Package in package.json dependencies but never imported in source code
  • postinstall script that is obfuscated, calls curl, 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.json changed 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 prepare or husky script alongside other changes (may indicate bypass of pre-commit checks)
  • New transitive dependency that doesn't appear to be pulled in by anything
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment