| name | plan-vulnerability-remediation |
| description | plan safe, idempotent remediation work for known dependency vulnerabilities. use when asked to triage CVEs, dependency alerts, security advisories, Dependabot alerts, or npm/yarn/pnpm/pip/bundler/cargo/go audit findings, and to group them into remediation PR plans before changing code. for CodeQL or code scanning alerts, use plan-code-scanning-remediation instead. |
Plan Vulnerability Remediation
Overview
Create an actionable, idempotent remediation plan for known dependency vulnerabilities before making changes. The plan consumes a stack of vulnerability findings from dependency scanners and GitHub Dependabot alerts, determines whether each finding is already addressed by an existing open PR or by the current dependency state, groups closely related vulnerabilities that can be fixed together, and emits one or more PR-ready remediation plans.
This skill is designed to pair with the remediate-vulnerability skill. Use this skill first when the user asks for automation, batching, triage, grouping, or a plan. Use remediate-vulnerability when it is time to implement one plan and open or update a PR.
For code scanning alerts (CodeQL, SAST), use plan-code-scanning-remediation instead.
Goals
- Be idempotent: rerunning should not create duplicate branches or PRs for the same vulnerability set.
- Prefer the smallest safe remediation that resolves the vulnerability.
- Group vulnerabilities only when doing so creates one coherent dependency change.
- Detect existing remediation PRs before starting new work.
- Produce enough structured information for an automated loop to process one plan at a time.
- Track longer-running remediation progress in a repository-local markdown file that can be read by later invocations.
Inputs
Accept vulnerability findings from any of these sources:
- User-provided CVE IDs, GHSA IDs, package names, versions, ecosystem names, severity, and advisory URLs.
- GitHub Dependabot alerts via
gh api or gh dependabot if available.
- Dependency audit commands such as
npm audit --json, pnpm audit --json, yarn npm audit --json, pip-audit --format json, bundle audit, cargo audit --json, govulncheck, or ecosystem-specific scanners.
- Security tracking issues or files in the repository.
Each finding should be normalized to these fields when possible:
id: CVE, GHSA, or scanner advisory identifier.
ecosystem: npm, pip, bundler, cargo, gomod, maven, gradle, nuget, docker, github-actions, etc.
package: affected package or component name.
current_version: vulnerable installed or resolved version.
fixed_versions: known safe version range(s), if available.
severity: critical, high, moderate, low, or unknown.
source: where the finding came from.
manifest_paths: package manifests likely affected.
lockfile_paths: lockfiles likely affected.
Safety rules
- Do not change source code, manifests, lockfiles, dependency files, or branches in this planning skill unless the user explicitly asks you to proceed with remediation.
- It is acceptable to create or update the progress tracker at
docs/tmp/vulnerability-remediation.md when planning a longer-running or automated remediation run. This tracker is the handoff artifact between planning and remediation.
- Treat vulnerability scanner output as advisory, not absolute truth. Verify against manifests, lockfiles, and installed dependency graphs when possible.
- Do not ignore a finding merely because a package name is absent from a top-level manifest; it may be transitive.
- Do not group unrelated major upgrades, unrelated ecosystems, or unrelated application code changes into one PR unless the user explicitly requests broad batching.
- Do not expose secrets from scanner output, environment files, package registries, or CI logs.
- Prefer read-only commands until the plan is accepted.
Workflow
1. Establish repository and tooling context
Identify the repository root and available package managers. Use read-only inspection first:
git status --short --branch
git remote -v
git branch --show-current
find . -maxdepth 3 \( -name package.json -o -name package-lock.json -o -name pnpm-lock.yaml -o -name yarn.lock -o -name pyproject.toml -o -name requirements.txt -o -name Pipfile.lock -o -name Gemfile.lock -o -name Cargo.toml -o -name Cargo.lock -o -name go.mod -o -name go.sum -o -name pom.xml -o -name build.gradle -o -name build.gradle.kts -o -name packages.lock.json -o -name composer.lock -o -name Dockerfile -o -name '*.csproj' -o -name '.github' \) -print
Determine:
- Base branch (
main, master, or repository default from gh repo view --json defaultBranchRef when available).
- Package ecosystems present.
- Monorepo package boundaries.
- Existing dependency update conventions such as Dependabot config, Renovate config, lockfile policy, and CI commands.
2. Gather vulnerability findings
If the user supplied specific findings, normalize those first.
If the user asks you to pull from GitHub, verify gh is available and authenticated:
gh --version
gh auth status
Then list open Dependabot alerts with useful fields:
gh api repos/:owner/:repo/dependabot/alerts --paginate --jq '.[] | {number, state, dependency: .dependency, security_advisory: .security_advisory, security_vulnerability: .security_vulnerability, html_url, created_at, fixed_at, dismissed_at}'
If local audit commands are appropriate, select commands based on discovered manifests. Prefer JSON output when available. Use timeouts for expensive commands. Examples:
npm audit --json
pnpm audit --json
yarn npm audit --json
pip-audit --format json
bundle audit
cargo audit --json
govulncheck ./...
If scanners require missing tools or credentials, note that in the plan instead of inventing results.
3. Check whether each finding is already resolved locally
For each finding:
- Inspect relevant manifests and lockfiles to find the resolved version.
- Compare the resolved version against the fixed version range.
- If the resolved version is already fixed on the current branch, mark the finding as
already-fixed-locally and do not plan a PR for it.
- If the package is absent, determine whether it is transitive and whether the dependency graph still includes it.
- If the scanner result is stale or cannot be reproduced, mark it as
needs-verification and include the exact verification gap.
Useful read-only commands by ecosystem:
npm ls <package> --all
pnpm why <package>
yarn why <package>
pip show <package>
pipdeptree --packages <package>
bundle info <gem>
cargo tree -i <crate>
go mod why -m <module>
mvn dependency:tree -Dincludes=<groupId>:<artifactId>
4. Check for existing open PRs that already address findings
Before proposing a new remediation PR, search open PRs. Use multiple signals because branch names and titles vary.
Fetch open PR metadata:
gh pr list --state open --limit 100 --json number,title,headRefName,baseRefName,body,labels,url,updatedAt
For each finding or candidate group, look for:
- CVE or GHSA ID in title, body, branch name, commits, or labels.
- Affected package name in title, body, branch name, or changed files.
- Dependabot or Renovate branches that update the affected package.
- Branch names created by this automation. Use the convention
security/<ecosystem>-<slug>-<advisory-or-package>.
Inspect likely PRs before deciding they match:
gh pr view <number> --json number,title,body,headRefName,baseRefName,state,mergeable,url
gh pr diff <number> --name-only
gh pr diff <number> -- <manifest-or-lockfile-path>
A PR counts as already addressing a finding only if its diff updates the vulnerable package, removes the vulnerable dependency path, or otherwise implements a credible mitigation. If uncertain, classify as possibly-covered-by-pr rather than creating a duplicate.
5. Group findings into remediation units
Create candidate remediation groups. Group findings when all or most of these are true:
- Same package, same ecosystem, or same dependency family.
- Same manifest and lockfile.
- Same direct dependency upgrade resolves multiple CVEs.
- Same transitive parent dependency upgrade resolves multiple CVEs.
- Same toolchain update, base image update, or GitHub Action version bump resolves multiple advisories.
- The upgrade path is small and coherent, such as one patch/minor version bump or one package family bump.
Do not group findings when any of these are true unless explicitly requested:
- Different ecosystems or unrelated manifests.
- Multiple major upgrades with separate migration risks.
- One finding needs application code changes while another only needs a lockfile update.
- Fixes have conflicting version constraints.
- Combining would make ownership, review, or rollback unclear.
Group priority:
- Critical and high severity exploitable findings.
- Findings with known fixes and low upgrade risk.
- Multiple findings resolved by one direct dependency update.
- Findings already covered by existing PRs should be marked and excluded from new work.
6. Define a remediation plan for each group
For every proposed group, include:
group_id: stable slug such as npm-express-cve-2024-12345 or pip-django-ghsa-abcd-1234.
findings: advisory IDs included.
ecosystem and package manager.
affected_packages and current versions.
target_versions or target dependency constraints.
manifest_paths and lockfile_paths to change.
branch_name: stable and deterministic, e.g. security/npm-express-cve-2024-12345.
pr_title: e.g. fix(security): update express to address CVE-2024-12345.
remediation_strategy: direct upgrade, transitive parent upgrade, lockfile refresh, replace dependency, configuration mitigation, code mitigation, base image update, or upstream PR already exists.
commands_to_run: package-manager commands expected to update only the intended files.
verification_commands: audit and test commands that should prove remediation.
existing_pr: PR URL or number if already covered.
risk_notes: major version changes, peer dependency risks, migrations, or uncertainty.
automation_status: one of ready, in-progress, pr-opened, covered-by-existing-pr, already-fixed-locally, needs-user-input, needs-verification, blocked, or done.
progress_notes: concise notes about decisions, blockers, or verification gaps.
last_updated: timestamp or date if known.
7. Create or update the progress tracker
For longer-running tasks, automated loops, or when the user asks for persistent tracking, create or update this repository-local file:
docs/tmp/vulnerability-remediation.md
If docs/tmp does not exist, create it. This file is the explicit handoff mechanism between plan-vulnerability-remediation and remediate-vulnerability. It should be committed only if the user wants task-tracking docs in the PR; otherwise it may remain as local working notes. Do not include sensitive scanner output.
Use this structure:
# Vulnerability Remediation Tracker
## Run metadata
- Started: <date/time if known>
- Repository: <owner/repo or remote URL>
- Base branch: <base branch>
- Sources: <Dependabot alerts, npm audit, user-provided CVEs, etc.>
- Tracker version: 1
## Status summary
- Ready: <count>
- In progress: <count>
- PR opened: <count>
- Covered by existing PR: <count>
- Already fixed locally: <count>
- Needs input: <count>
- Blocked: <count>
- Done: <count>
## Remediation queue
### <group_id>
- Status: ready
- Branch: security/<group_id>
- PR: <none or URL>
- Findings: <CVE/GHSA IDs>
- Ecosystem: <ecosystem>
- Packages: <package current -> target>
- Manifests: <paths>
- Lockfiles: <paths>
- Strategy: <direct upgrade/transitive parent upgrade/etc.>
- Commands:
- `<command>`
- Verification:
- `<command>`
- Risk notes: <notes>
- Progress notes:
- <timestamp or date> — planned remediation group
Keep each remediation group under a stable ### <group_id> heading so later runs can find and update it. Preserve existing notes and append new progress notes instead of replacing history.
When rerunning the planner:
- Read the existing tracker first if it exists.
- Preserve groups that are
in-progress, pr-opened, blocked, or done unless the current repository state proves they should change.
- Add newly discovered groups.
- Update statuses for findings that are now covered by PRs or fixed locally.
- Avoid reordering groups unless doing so materially improves priority.
8. Handoff contract for remediate-vulnerability
There are two supported handoff modes:
- Conversation handoff — output a full group plan in the response and then invoke
remediate-vulnerability with that group in the conversation context.
- Tracker-file handoff — write the group plan into
docs/tmp/vulnerability-remediation.md; remediate-vulnerability reads the next Status: ready group from the tracker and updates that same section as it works.
For automated or long-running work, prefer tracker-file handoff. The tracker is the durable queue and audit log. remediate-vulnerability should process exactly one ready group per invocation, then update that group's status and notes.
9. Output an automation-friendly summary
When the user wants a loop-friendly output, end with a concise queue:
READY:
1. <group_id> — <branch_name> — <short remediation summary>
SKIP:
1. <finding id> — already fixed locally
2. <finding id> — covered by <PR URL>
NEEDS INPUT:
1. <group_id> — reason
If the user asks for JSON, produce valid JSON with an array of remediation groups and no markdown decorations.
Idempotency contract
A subsequent run should make the same decision for the same repository state. Preserve idempotency by using:
- Stable
group_id values derived from ecosystem, package, and advisory IDs.
- Stable branch names derived from
group_id.
- PR titles containing
fix(security) plus package and advisory identifiers when available.
- PR bodies containing a machine-readable marker:
<!-- vulnerability-remediation: group_id=<group_id>; findings=<comma-separated ids>; packages=<comma-separated packages> -->
On rerun, search for this marker in open PR bodies before creating any new plan. Also read docs/tmp/vulnerability-remediation.md when present and reconcile tracker state with live repository and PR state.
When to hand off to remediate-vulnerability
Use remediate-vulnerability for each plan with automation_status: ready or tracker Status: ready.
If using conversation handoff, pass along:
- Full group plan.
- Existing branch name if present.
- Exact files to change.
- Exact commands to run.
- Verification commands.
- Existing PR markers to reuse.
If using tracker-file handoff, tell remediate-vulnerability to read docs/tmp/vulnerability-remediation.md and process the next Status: ready group. The tracker section for that group is the durable handoff record.
Final response
Report:
- Number of findings examined.
- Path to the progress tracker if created or updated.
- Findings already fixed locally.
- Findings covered by existing PRs.
- Proposed remediation groups ready for implementation.
- Findings that need user input or manual verification.
- The next
group_id that remediate-vulnerability should process, if any.
- Recommended next command or next skill invocation.