| name | fix-npm-vulnerability |
| description | Fix a pnpm/npm security advisory in a pnpm monorepo. First attempts to update the head dependency; falls back to a pnpm override with a tracking GitHub issue. Use when pnpm audit or Dependabot surfaces a vulnerability. |
| allowed-tools | Bash(*) Read(*) Edit(*) WebSearch(*) |
Fix npm Vulnerability
You are resolving a security advisory in a pnpm monorepo.
Step 0 — Gather the advisory details
Ask the user for one or both of:
What vulnerability do you want to fix?
Provide a CVE ID (e.g. CVE-2026-44705), GHSA slug (e.g. GHSA-w7jw-789q-3m8p), or vulnerable package name.
Optionally paste the pnpm audit output line for it.
Wait for the answer before proceeding.
Step 1 — Locate the workspace root
Find the directory containing pnpm-workspace.yaml, starting from the current directory and walking up:
dir=$(pwd); while [ "$dir" != "/" ]; do [ -f "$dir/pnpm-workspace.yaml" ] && echo "$dir" && break; dir=$(dirname "$dir"); done
If nothing is found, ask the user to navigate to the monorepo root first.
All subsequent commands run from this root.
Step 2 — Get the full audit picture
pnpm audit --json 2>/dev/null | jq '.advisories // .vulnerabilities // .' 2>/dev/null | head -400
Identify for each advisory matching the user's input:
vulnerablePackage — the transitive package that contains the flaw
patchedVersions — the version range that fixes it (e.g. >=4.0.6)
via — the dependency chain showing which head (direct workspace) dep pulls it in
advisoryId — CVE or GHSA identifier
severity — high / critical
Step 3 — Traverse the dependency chain
Use pnpm why to confirm the full chain from the workspace to the vulnerable package:
pnpm why <vulnerable-package> 2>&1 | head -60
This shows every head dep that transitively depends on it. Record:
- The head package(s) (direct workspace deps) pulling in the vulnerable version
- The current version of those head packages
Step 4 — Check if updating the head dep resolves the issue
For each head package, inspect what version of the vulnerable package its latest release ships:
npm info <head-package> version
npm info <head-package>@latest dependencies --json 2>/dev/null | jq '.<vulnerable-package> // "not direct"'
npm info <head-package>@latest peerDependencies --json
For transitive chains deeper than one level, check the registry manifest:
npm pack <head-package>@latest --dry-run --json 2>/dev/null | head -50
Decision:
A. If the latest <head-package> ships <vulnerable-package> at a version satisfying <patchedVersions>:
→ The update resolves the issue. Continue to Step 5a.
B. If the latest <head-package> still ships the vulnerable version (fix not yet released upstream):
→ An override is required. Continue to Step 5b.
Step 5a — Update the head dependency
Check whether this is a major version bump:
current=$(node -p "require('./node_modules/<head-package>/package.json').version" 2>/dev/null)
latest=$(npm info <head-package> version)
echo "current=$current latest=$latest"
If it IS a major bump, before touching any files, generate testing guidance (Step 6) and show it to the user. Ask:
This is a major version upgrade for <head-package> (<current> → <latest>).
I've listed the affected workspaces and test commands above.
Shall I proceed with the upgrade?
Wait for confirmation.
Update the dep:
pnpm update <head-package>@latest
Verify the vulnerable package is now at the patched version:
pnpm why <vulnerable-package> 2>&1 | grep -E "version|<vulnerable-package>"
pnpm audit --audit-level=high 2>&1 | grep -c "high\|critical" && echo "ISSUES REMAIN" || echo "CLEAN"
If clean, skip Steps 5b, 7, and 8. Report the upgrade (and testing checklist if it was a major bump).
Step 5b — Add the pnpm override
First create the GitHub issue (Step 7) so you have the URL to embed in the comment.
Then open pnpm-workspace.yaml and add under overrides::
<vulnerable-package>: '<patchedVersion>'
Use scoped syntax when the vulnerability is only reachable through one specific head dep:
<head-package>><vulnerable-package>: '<patchedVersion>'
Match the comment and formatting style of existing entries in the file.
The override needs pnpm install to take effect in the lockfile — that regenerates resolutions
for the whole tree, not just the pinned package, so it can pull in unrelated drift (a transitive
dep bumping a patch version elsewhere). Ask before running it:
I've added the override to pnpm-workspace.yaml. Running pnpm install now will regenerate
pnpm-lock.yaml to match — that can also shift unrelated transitive versions. Shall I proceed?
Wait for confirmation, then run:
pnpm install
pnpm audit --audit-level=high 2>&1 | grep -c "high\|critical" && echo "ISSUES REMAIN" || echo "CLEAN"
Make sure pnpm-lock.yaml ends up staged/committed together with the pnpm-workspace.yaml edit —
don't leave the lockfile change uncommitted for a later, unrelated commit to pick up.
Step 6 — Testing guidance (major version bumps only)
When the head dep crosses a major version, output a checklist before applying the change.
Affected workspaces — every workspace that depends on <head-package>:
grep -rl '"<head-package>"' --include='package.json' . | grep -v node_modules
Changelog / breaking changes — fetch release notes:
npm info <head-package>@latest 2>/dev/null | grep -A5 "homepage\|repository"
Then WebSearch for "<head-package> v<major> migration guide" or its changelog.
Test commands to run after the upgrade:
- For each affected workspace:
pnpm --filter <workspace> test
- If the workspace has a dev server:
pnpm --filter <workspace> dev — note which URLs or UI flows exercise this package
- Run the full audit:
pnpm audit --audit-level=high
Present this as a numbered checklist the developer can follow manually after the PR lands.
Step 7 — Create the tracking GitHub issue (override path only)
Detect the remote:
git remote get-url origin 2>/dev/null
gh issue create \
--title "[Dependency Management 🔒] Remove Pnpm Override for <vulnerable-package> Once <head-dep> Ships the Fix" \
--label "security,maintenance" \
--body "$(cat <<'EOF'
## Tracking Override Added on <YYYY-MM-DD>
| Field | Value |
|---|---|
| Advisory | <CVE/GHSA-slug> |
| Vulnerable package | `<vulnerable-package>` |
| Fix requires | `<vulnerable-package>@<patchedVersions>` |
| Blocked by | `<head-dep>` — fix not yet released upstream |
| Override location | `pnpm-workspace.yaml` |
## How to Remove
Once `<head-dep>` publishes a release that includes `<vulnerable-package>@<patchedVersions>`:
1. Delete the override line from `pnpm-workspace.yaml`
2. Run `pnpm install`
3. Run `pnpm audit --audit-level=high` to confirm it is clean
EOF
)"
Capture the returned issue URL. Use it in the # Tracking: comment in Step 5b.
If security or maintenance labels don't exist in the repo, omit --label rather than failing.
Step 8 — Final report
If upgraded:
- Package upgraded and the fix confirmed clean
- Testing checklist (if major bump)
If overridden:
- Exact lines added to
pnpm-workspace.yaml
- GitHub issue URL
- When to revisit: "Once
<head-dep> releases with <vulnerable-package>@<patchedVersions>, delete the override line and run pnpm install && pnpm audit --audit-level=high"