| name | remediate-vulnerability |
| description | implement an idempotent dependency vulnerability remediation plan, update dependencies, verify the fix, commit, push, and create or update a pull request. use after planning CVE/GHSA/dependency alert remediation or when asked to automatically fix one dependency vulnerability group. for CodeQL or code scanning fixes, use remediate-code-scanning instead. |
Remediate Vulnerability
Overview
Implement one coherent dependency vulnerability remediation unit safely and idempotently. This skill takes a plan from plan-vulnerability-remediation or enough vulnerability details from the user, checks whether the work is already covered, applies the smallest safe dependency fix, verifies the result, commits the intended changes, pushes a deterministic branch, and creates or updates a pull request.
The intended automation model is: take one ready remediation group off the queue, run this skill, update progress, and stop after one PR is created or updated. A loop can then invoke the skill again for the next group.
For code scanning (CodeQL/SAST) fixes, use remediate-code-scanning instead.
For longer-running or automated work, the queue and progress log should live in docs/tmp/vulnerability-remediation.md. This tracker is created by plan-vulnerability-remediation and consumed by this skill.
Idempotency requirements
Rerunning this skill for the same group must not create duplicate branches or PRs.
Use these stable identifiers:
group_id: from the plan, or derive from ecosystem + package + advisory IDs, e.g. npm-express-cve-2024-12345.
branch_name: security/<group_id> unless the plan specifies another deterministic branch.
- PR marker in the PR body:
<!-- vulnerability-remediation: group_id=<group_id>; findings=<comma-separated ids>; packages=<comma-separated packages> -->
Before creating new work, search for:
- An open PR containing the marker.
- An open PR mentioning the advisory IDs and affected package names.
- An existing local or remote branch with the deterministic branch name.
- Dependabot or Renovate PRs that already update the affected package.
If a matching open PR already addresses the finding, update that PR only if necessary and do not open another PR.
Inputs
There are two supported input modes:
- Tracker-file input — read
docs/tmp/vulnerability-remediation.md and process exactly one group with Status: ready. Prefer this mode for long-running or automated remediation loops.
- Conversation input — consume one remediation group supplied directly in the conversation by
plan-vulnerability-remediation or the user.
Prefer a remediation group from plan-vulnerability-remediation with:
group_id
findings
ecosystem
affected_packages
current_version
target_versions
manifest_paths
lockfile_paths
branch_name
pr_title
remediation_strategy
commands_to_run
verification_commands
risk_notes
If no plan exists, first check whether docs/tmp/vulnerability-remediation.md exists. If it exists, use the next Status: ready group from that file. If it does not exist, gather enough information to create a minimal plan first. If there are multiple unrelated vulnerabilities, switch to plan-vulnerability-remediation rather than guessing how to batch them.
Safety rules
- Never run destructive git commands such as
git reset --hard, git clean, force-push, rebase, or amend unless the user explicitly requests that exact operation.
- Do not make dependency upgrades broader than needed to address the vulnerability unless the package manager requires it or the plan explicitly says so.
- Do not commit secrets, local environment files, dependency folders, caches, generated build artifacts, or unrelated user changes.
- Do not overwrite unrelated uncommitted changes. If the working tree is dirty, inspect and either include only related files or stop for user input.
- Avoid direct pushes to protected base branches such as
main, master, develop, or release branches.
- Keep PRs focused. One remediation group should produce one branch and one PR.
- State clearly if verification could not be completed.
Workflow
1. Load the tracker or supplied group
If docs/tmp/vulnerability-remediation.md exists and the user did not supply a specific group, read it and select the first remediation group under ## Remediation queue with Status: ready. Process exactly one group per invocation.
If the user supplies a group_id, read the matching ### <group_id> section from the tracker when present. If the same group is also supplied in conversation, reconcile them and prefer the most recent concrete repository facts.
If using tracker-file input, update the selected group immediately before making changes:
- Change
Status: ready to Status: in-progress.
- Append a progress note that remediation started.
- Preserve all previous progress notes.
- Do not remove other groups.
If no tracker exists and no group is supplied, gather enough details to produce a one-group plan or ask the user to run plan-vulnerability-remediation first.
2. Confirm repository state and base branch
Start with read-only inspection:
git status --short --branch
git branch --show-current
git remote -v
git fetch origin
Determine the default/base branch:
gh repo view --json defaultBranchRef
If gh is unavailable or unauthenticated, you may still make local changes, but you cannot check or create PRs. Tell the user exactly what is blocked.
3. Normalize or confirm the remediation group
If the plan is supplied, restate the key facts:
- Advisory IDs.
- Affected package(s) and current version(s).
- Target version or mitigation.
- Files expected to change.
- Verification commands.
If only a CVE/GHSA/package is supplied, gather minimal context and produce a plan inline. If the fix is ambiguous, stop and ask for input rather than applying an arbitrary major upgrade.
4. Check for existing remediation PRs
Search open PRs before changing files:
gh pr list --state open --limit 100 --json number,title,headRefName,baseRefName,body,labels,url,updatedAt
A PR counts as matching if it has the marker for this group_id, or if it credibly updates/removes the affected package for the listed advisory IDs.
For likely matches, inspect the diff:
gh pr view <number> --json number,title,body,headRefName,baseRefName,state,url,mergeable
gh pr diff <number> --name-only
gh pr diff <number> -- <manifest-or-lockfile-path>
Outcomes:
- If an open PR already fixes the vulnerability, update the tracker group to
Status: covered-by-existing-pr, set PR: <url>, append the evidence as a progress note, report the PR URL, and stop.
- If an open PR exists for this branch/group but is incomplete or stale, update the tracker group to
Status: in-progress, set PR: <url>, check out that branch, and continue remediation there.
- If no matching PR exists, continue.
5. Prepare the deterministic branch
Use the planned branch name, usually security/<group_id>.
Check for existing branches:
git branch --list <branch_name>
git ls-remote --heads origin <branch_name>
If the current branch is a protected base branch, create or check out the remediation branch:
git checkout -b <branch_name> origin/<base_branch>
If the remote branch already exists, check it out safely:
git checkout -B <branch_name> --track origin/<branch_name>
If the current branch is already the deterministic remediation branch, continue.
If the current branch is some other feature branch with unrelated work, stop and ask whether to switch branches.
6. Verify current vulnerability state
Before applying changes, verify whether the current branch is still vulnerable.
Use package-manager-specific inspection, examples:
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>
If the current branch already resolves the vulnerability, do not create an empty PR. Update the tracker to Status: already-fixed-locally or Status: done as appropriate, append verification evidence, and stop. If the existing branch has no PR, optionally create a PR only when there are relevant committed changes not yet proposed.
7. Apply the smallest safe remediation
Follow the plan's commands_to_run when available. Prefer commands that target only the affected package or parent package.
Common patterns:
npm
npm install <package>@<fixed-version-or-range>
npm update <package>
npm audit fix --package-lock-only
pnpm
pnpm update <package>@<fixed-version-or-range>
pnpm audit --fix
Yarn classic or berry
yarn up <package>@<fixed-version-or-range>
yarn npm audit
Python
python -m pip install --upgrade <package>
pip-compile --upgrade-package <package>
poetry update <package>
uv lock --upgrade-package <package>
Choose the command that matches the repository's dependency management files.
Ruby
bundle update <gem>
Rust
cargo update -p <crate> --precise <version>
Go
go get <module>@<version>
go mod tidy
Maven/Gradle
Update the version declaration or dependency constraints, then refresh dependency locks if the repo uses them.
Docker/base images
Update the affected base image tag or digest, prefer a supported fixed version, and avoid floating tags unless that is the repository convention.
GitHub Actions
Update vulnerable action versions in .github/workflows. Prefer pinned fixed versions or SHAs if the repo uses pinning.
If package-manager commands modify unrelated dependency files, inspect the diff carefully. Revert only unrelated changes when it is safe and non-destructive to do so by editing files back or rerunning targeted commands. Do not use destructive git restore/reset without explicit permission.
8. Inspect the diff
After changes:
git status --short
git diff --stat
git diff --name-status
git diff -- <manifest-or-lockfile-path>
Confirm:
- Changed files match the plan.
- Vulnerable packages were updated, removed, or mitigated.
- No unrelated user changes are included.
- No secrets or local artifacts were introduced.
If unexpected files changed, determine whether they are required lockfile or generated metadata changes. If unrelated, stop and ask before proceeding.
9. Verify remediation
Run the plan's verification_commands. At minimum, rerun the relevant audit or dependency graph command when available.
Examples:
npm audit --json
pnpm audit --json
yarn npm audit --json
pip-audit --format json
bundle audit
cargo audit --json
govulncheck ./...
Also run focused tests if the repository exposes a clear command and the change has runtime risk:
npm test
pnpm test
pytest
bundle exec rspec
cargo test
go test ./...
mvn test
gradle test
Use timeouts for expensive commands. If tests or audits fail:
- Separate pre-existing unrelated failures from remediation failures when possible.
- Fix remediation-caused failures if the root cause is clear.
- Do not broaden the upgrade scope repeatedly without reassessing the plan.
- If blocked, leave changes in place and report exact failures.
10. Commit the remediation
Stage only intended files:
git add <manifest-paths> <lockfile-paths> <code-or-config-mitigation-paths>
Inspect staged changes:
git diff --cached --stat
git diff --cached --name-status
git diff --cached
Use a conventional security commit message:
fix(security): address <advisory-or-package> vulnerability
Update <package(s)> to a fixed version to resolve <CVE/GHSA IDs>. Include lockfile updates generated by <package manager>.
If multiple findings are intentionally grouped, mention all IDs in the body.
Commit:
git commit -m "fix(security): address <package> vulnerabilities" -m "Update <package(s)> to fixed versions for <advisory IDs>."
If there are no staged changes after verification, do not commit. Report that the vulnerability appears already remediated or that no safe change was found.
11. Push and create or update the PR
Push the deterministic branch:
git push -u origin <branch_name>
Search again for a PR with this branch or marker:
gh pr list --state open --head <branch_name> --json number,title,url,body
If the PR exists, update its title/body if needed. If no PR exists, create it:
gh pr create --draft --title "<pr_title>" --body "<pr_body>" --base <base_branch> --head <branch_name>
Use this PR body structure:
<!-- vulnerability-remediation: group_id=<group_id>; findings=<comma-separated ids>; packages=<comma-separated packages> -->
## Summary
- Updates or mitigates `<package>` to address `<advisory IDs>`.
- Changes `<manifest/lockfile paths>`.
- Uses `<remediation strategy>`.
## Vulnerabilities addressed
- `<advisory ID>` — `<package>` `<current version>` → `<fixed version or mitigation>`
## Verification
- [x] `<audit or graph command>`
- [x] `<test command>`
## Risk notes
- `<major version changes, peer dependency impacts, or "No major-version upgrade required.">`
For failed or skipped verification, use unchecked boxes and explain why:
- [ ] `<command>` — not run because `<reason>`
After creation or update, verify live PR metadata:
gh pr view <number-or-url> --json number,title,body,url,headRefName,baseRefName,state
12. Update the progress tracker
If docs/tmp/vulnerability-remediation.md exists, update the selected group's section before the final response:
- Set
Status: pr-opened when a PR was created or updated and still needs review/merge.
- Set
Status: done only when the vulnerability is verified fixed and there is no remaining PR work needed, such as when it was already fixed locally or an existing merged state is confirmed.
- Set
Status: blocked when remediation cannot proceed due to tooling, registry, merge conflicts, unavailable fixed versions, unclear major upgrade risk, or failing verification that cannot be resolved safely.
- Set
PR: <url> when a PR exists.
- Append progress notes for commands run, files changed, verification results, commit hash, PR URL, and blockers.
- Update the
## Status summary counts so they match group statuses.
- Preserve historical notes and all unrelated group sections.
Do not commit the tracker file by default. Commit it only if the user explicitly wants the tracker included in the remediation PR.
13. Final response
Report:
- Remediation group ID and advisory IDs.
- Tracker path and final tracker status, if used.
- Branch name.
- Commit hash and commit message, if created.
- PR URL, or existing PR URL if already covered.
- Files changed.
- Verification commands and results.
- Any residual risk, blocked findings, or follow-up required.
- Whether the tracker file was left uncommitted.
Handling common situations
Existing PR already covers the vulnerability
Do not create a duplicate. Report the existing PR and the evidence that it covers the vulnerability, such as changed package/version or marker.
Existing deterministic branch exists without a PR
Check out the branch, inspect its diff and commits, verify whether it remediates the vulnerability, then push/create the PR if appropriate.
Vulnerability requires a major upgrade
Prefer planning first. If already in remediation, implement only when the plan identifies the migration scope. Run tests. Include major-upgrade risk notes in the PR body.
No fixed version exists
Do not fake a dependency update. Consider mitigations such as disabling affected functionality, changing configuration, applying a vendor patch, replacing a dependency, or documenting compensating controls. Mark the PR title/body clearly as a mitigation rather than an upgrade.
Transitive-only vulnerability
Identify the parent dependency that introduces the vulnerable package. Prefer updating the direct parent dependency or refreshing the lockfile to a fixed transitive version. Do not add a new direct dependency override unless it is the repository convention or the safest available fix.
Multiple vulnerabilities resolved by one update
Keep them in one PR if they share the same package, parent dependency, manifest, and lockfile. Include every advisory ID in the marker and PR body.
Scanner still reports the vulnerability after update
Inspect whether another dependency path still pulls in a vulnerable version. Use dependency tree commands to locate remaining paths. If there are multiple independent paths, either broaden the same coherent PR or stop and return a new plan for the remaining findings.
Package manager or registry failure
Report the exact command and error. Do not switch package managers. Do not hand-edit lockfiles unless the repository convention supports that and the change is trivial and reviewable.