- 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:
```bash
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
```bash
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:
```bash
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:
```bash
# Latest available version of the head dep
npm info <head-package> version
# Its full dependency tree for the vulnerable package
npm info <head-package>@latest dependencies --json 2>/dev/null | jq '.<vulnerable-package> // "not direct"'
# If it's deeper, check peer dependencies too
npm info <head-package>@latest peerDependencies --json
```
For transitive chains deeper than one level, check the registry manifest:
```bash
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**:
```bash
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:
```bash
pnpm update <head-package>@latest
```
Verify the vulnerable package is now at the patched version:
```bash
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:`:
```yaml
# JUSTIFICATION: Fixes <CVE/GHSA-slug> — <one-line description of the flaw>.
# Added <YYYY-MM-DD>. Remove once <head-dep> ships a release containing <vulnerable-package>@<patchedVersions>.
# Tracking: <github-issue-url>
<vulnerable-package>: '<patchedVersion>'
```
Use scoped syntax when the vulnerability is only reachable through one specific head dep:
```yaml
<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:
```bash
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>`:
```bash
grep -rl '"<head-package>"' --include='package.json' . | grep -v node_modules
```
**Changelog / breaking changes** — fetch release notes:
```bash
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:
```bash
git remote get-url origin 2>/dev/null
```
```bash
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`"
عرض على GitHub