{"uuid": "b5e08a84-aad8-40c7-ac4a-01fbc71f51ad", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "GHSA-xxxx-xxxx-xxxx", "type": "seen", "source": "https://gist.github.com/tieubao/1732a4285d558ffcc1a1277918bef8b5", "content": "---\nname: patch-exploit\ndescription: &gt;-\n  Use when the user shares a vulnerability, exploit, or security advisory\n  (CVE link, GHSA, X/Twitter post, vendor blog, `npm audit` output) and wants\n  their repos audited and patched. Trigger phrases include \"there's an exploit\n  at \", \"patch this CVE\", \"audit for \", \"is X vulnerable to ?\",\n  \"we got hit by \", any pasted CVE-ID / GHSA-ID / security advisory URL.\n  Parses the advisory (npm / pip / uv / go / cargo / gem / cf-worker), sweeps\n  the configured workspace for matching packages, triages by deployment status,\n  then patches vulnerable+deployed repos one-by-one with per-repo confirmation,\n  verification, and a `fix/` commit. NOT for: zero-context \"look for\n  vulns in my code\" (that's a generic audit, no advisory anchor); host-OS CVEs\n  (kernel, openssh, macOS); CVEs in client repos owned by other engineers.\n---\n\n# patch-exploit\n\nA Claude Code skill: when the user drops a vulnerability link or CVE ID, this skill audits their repos and patches the vulnerable ones with per-repo confirmation.\n\n## Install\n\n1. Save this file as `~/.claude/skills/patch-exploit/SKILL.md`.\n2. Set `WORKSPACE_ROOT` to where your repos live (defaults to `~/workspace/`).\n3. Optional: set `PATCH_EXPLOIT_LOG` to a markdown file path if you want each run logged (one prepended entry per run). Leave unset to skip logging.\n\nThe skill is invoked automatically by Claude Code when the user types a trigger phrase or pastes a CVE/GHSA URL. No slash command needed.\n\n## Activation\n\nFire on **any** of:\n\n- A URL pointing at: x.com / twitter.com (security researcher post), `github.com/advisories/GHSA-*`, `nvd.nist.gov`, `cve.org`, vendor security blogs (vercel.com/security, nodejs.org/security, etc.).\n- A bare CVE-ID (`CVE-YYYY-NNNNN`) or GHSA-ID (`GHSA-xxxx-xxxx-xxxx`).\n- Pasted `npm audit` / `pnpm audit` / `pip-audit` / `cargo audit` / `govulncheck` output.\n- The phrases: \"there's an exploit\", \"patch this CVE\", \"audit for \", \"is X vulnerable to ?\", \"we got hit by \".\n\nDo **not** fire when the user is asking a general-knowledge question about a CVE (no audit/patch ask), or when the advisory is for the host OS / kernel / sshd (host-side patching is not in scope; surface \"this is a host patch, not a repo patch\" instead).\n\n## Workflow\n\n### 1. Parse the advisory\n\nExtract these fields. Refuse to proceed if **affected package** + **vulnerable range** + **fix version** cannot all be pinned. Ask the user to clarify rather than guessing.\n\n| Field | How to get it |\n|---|---|\n| Affected package(s) | Advisory body |\n| Ecosystem | npm, pip/uv, go, cargo, gem, cf-worker-binding, etc. |\n| Vulnerable version range | e.g. `&gt;=13.4.13 &lt;15.5.16 \\|\\| &gt;=16.0.0 &lt;16.2.5` |\n| Fix version(s) | The lowest patched release per branch |\n| Attack vector | One-line summary (RCE, SSRF, prototype pollution, etc.) |\n| Hosting caveat | Self-hosted only? Browser-side only? Requires  enabled? |\n| CVSS / severity | If listed |\n\n**Source-specific fetch:**\n\n- **x.com / twitter.com**: `curl -s https://api.fxtwitter.com//status/ | jq '.tweet'`. The site itself returns a 302 to a login wall; fxtwitter exposes the tweet body as JSON. Mirror services like vxtwitter / supadata can lag or fail.\n- **GitHub Security Advisory**: `gh api /advisories/GHSA-xxxx-xxxx-xxxx` returns JSON with `vulnerabilities[].vulnerable_version_range` and `vulnerabilities[].first_patched_version.identifier`.\n- **NVD / cve.org**: WebFetch the page, then ask the user to confirm the version range if the page is ambiguous (NVD often is).\n- **Vendor blog**: WebFetch.\n\n### 2. Sweep the workspace\n\nDefault scope: `$WORKSPACE_ROOT` (or `~/workspace/` if unset). The user can override at invocation time (\"just this repo\", \"include `~/clients/`\", etc.).\n\nManifest files per ecosystem:\n\n| Ecosystem | Declared | Locked |\n|---|---|---|\n| npm/pnpm/yarn | `package.json` | `pnpm-lock.yaml` / `package-lock.json` / `yarn.lock` |\n| Python (uv/pip/poetry) | `pyproject.toml` | `uv.lock` / `requirements.txt` (frozen) / `poetry.lock` |\n| Go | `go.mod` | `go.sum` |\n| Rust | `Cargo.toml` | `Cargo.lock` |\n| Ruby | `Gemfile` | `Gemfile.lock` |\n| Cloudflare Worker binding | `wrangler.toml` `compatibility_date` | n/a |\n\nScan command template (npm example):\n\n```bash\ncd \"$WORKSPACE_ROOT\" &amp;&amp; find . -name 'package.json' \\\n  -not -path '*/node_modules/*' \\\n  -not -path '*/.next/*' \\\n  -not -path '*/dist/*' \\\n  -not -path '*/build/*' 2&gt;/dev/null\n```\n\nFor each manifest hit, read:\n\n1. Declared version (`jq '.dependencies.\"\" // .devDependencies.\"\"'` for npm).\n2. Locked version from the lockfile (regex on `pnpm-lock.yaml`, `jq` on `package-lock.json`, etc.). Locked wins; declared is just the constraint.\n3. Deployment evidence: `vercel.json`, `wrangler.toml`, `Dockerfile`, `fly.toml`, `.vercel/`, `netlify.toml`, a `deploy` job in `.github/workflows/*.yml`, a LaunchAgent/Daemon plist under `tools/*/deploy/`, a `systemd` unit. Absence of all = local-only.\n\n### 3. Triage table\n\nPrint this exact format. Keep it scannable.\n\n```\n| Repo                  | Pkg     | Declared | Locked  | Vulnerable | Deployed | Verdict   |\n|-----------------------|---------|----------|---------|------------|----------|-----------|\n| myorg/web-app         | next    | ^14.2.0  | 14.2.3  | Yes        | Yes      | Urgent    |\n| myorg/internal-tool   | next    | ^15.5.0  | 15.5.20 | No         | Yes      | Past-fix  |\n| myorg/scratch/trial   | next    | 16.2.6   | 16.2.6  | No         | No       | Skip      |\n```\n\nVerdicts:\n\n- **Urgent**: vulnerable + deployed. Patch this session.\n- **Low**: vulnerable + local-only. Patch but no rush; bundle with next maintenance.\n- **Past-fix**: locked version &gt;= fix version. Note only.\n- **Skip**: not vulnerable OR third-party clone that you do not maintain.\n\n### 4. Patch (per repo, with confirmation)\n\nFor each **Urgent** or **Low** row, **ask the user before running anything**. One AskUserQuestion per repo (do not batch). Show:\n\n- The current locked version\n- The target fix version\n- The exact command you will run\n- The verification you will run after (tests / build / lint, per repo norms)\n\nPatch command per ecosystem (use the lockfile-aware form):\n\n| Ecosystem | Upgrade command |\n|---|---|\n| pnpm | `pnpm up @` (project root) |\n| npm | `npm install @ --save-exact` then `npm install` to refresh lockfile |\n| yarn | `yarn upgrade @` |\n| uv | `uv lock --upgrade-package ` then verify with `uv pip list \\| grep ` |\n| pip (frozen) | `pip install --upgrade ==` then `pip freeze &gt; requirements.txt` |\n| poetry | `poetry update ` (or `poetry add @^`) |\n| go | `go get @` then `go mod tidy` |\n| cargo | `cargo update -p  --precise ` |\n| bundler | `bundle update  --conservative` |\n\n**Major-version bumps are not silent.** If the user-chosen fix crosses a major (e.g. Next.js 14 \u2192 16), call this out explicitly in the per-repo confirmation. Major bumps may need migration work beyond a lockfile change. Offer the in-major alternative (e.g. \"your branch is 15.x; the same fix lives at 15.5.16, no major bump needed\") when one exists.\n\n### 5. Verify\n\nAfter the upgrade, run **before** committing:\n\n1. Install: `pnpm install` / `uv sync` / `go mod tidy` / `cargo build` (depending on ecosystem). If install fails, stop. Surface the error verbatim and ask.\n2. Tests: look for `package.json` scripts (`test`, `typecheck`, `lint`, `build`), `pyproject.toml` `[tool.pytest]`, `go test ./...`, `cargo test`. Run what exists. Skip what doesn't (do not invent a test command).\n3. Build: if a build script exists, run it.\n\nIf any step fails, **do not commit**. Surface the failure and ask the user. Max 5 fix attempts before escalating.\n\n### 6. Commit\n\nBranch name: `fix/` (e.g. `fix/cve-2026-nextjs-86`, `fix/next-16-2-5`). Kebab-case, no owner prefix, no dates, no spec IDs.\n\nCommit message (conventional commits):\n\n```\nfix(): bump  to  for \n\n\n\nRefs: \n```\n\nDo **not** push without explicit user instruction.\n\n### 7. Log (optional)\n\nIf the environment variable `PATCH_EXPLOIT_LOG` points at a markdown file, prepend a 3-6 line entry at the top of that file. Format:\n\n```markdown\n## YYYY-MM-DD (patch-exploit run, ): \n\nAdvisory: . Affected:  . Fix: .\n\nSwept `$WORKSPACE_ROOT`: N repos with , M vulnerable, K deployed. Patched: . Skipped past-fix: .\n\nVerification: . Branches: `fix/` in .\n```\n\nIf `PATCH_EXPLOIT_LOG` is unset, skip this step entirely.\n\nIf the variable is set and no vulnerable repos were found, still write one line so the audit is recorded.\n\n## Output format during the run\n\nUser-facing updates should be tight. Don't narrate every grep. Status checkpoints only:\n\n- After parse: \"Advisory parsed. Affected:  . Fix: . Sweeping .\"\n- After sweep: print the triage table.\n- Per repo patch: AskUserQuestion with the exact command.\n- Per repo verify: print the test/build output verbatim on failure, \"passed: \" on success.\n- End: print the log entry that was written (or \"no log file configured\").\n\n## Negative cases (when this skill should hand off)\n\n| Situation | Where to route |\n|---|---|\n| Host-OS CVE (kernel, openssh, macOS Safari) | Tell the user: \"this is a host patch, not a repo patch. Run `brew upgrade` / Software Update / `apt upgrade` on the affected host.\" Do not pretend to patch. |\n| Generic \"audit my code for vulns\" with no advisory | Use `npm audit` / `pnpm audit` / `pip-audit` / `cargo audit` / `gh dependabot alerts` first. Surface results, then loop back to this skill per-advisory. |\n| CVE in a client repo (not owned) | Stop. Tell the user the client owns the patch; if they want a PR, ask for explicit go-ahead. |\n| Cloudflare Worker compat-date issue (not a package, a binding) | Different patch shape (edit `wrangler.toml` + redeploy). Handle inline, but do not try to use a package-manager command. |\n\n## Configuration summary\n\n| Env var | Purpose | Default |\n|---|---|---|\n| `WORKSPACE_ROOT` | Root path to sweep | `~/workspace/` |\n| `PATCH_EXPLOIT_LOG` | Optional markdown log file | unset (no logging) |\n\nDefault autonomy: **confirm per repo, then patch + verify + commit**. The user can override at invocation time (\"just report\", \"auto-patch deployed\").\n\nSkill version: 0.1.0\n", "creation_timestamp": "2026-05-15T08:36:22.000000Z"}