Resolve GitHub security alerts (Dependabot, code scanning, secret scanning) across pip / pip-tools / poetry / uv / npm / yarn / pnpm / cargo / go-modules / Docker / GitHub Actions ecosystems. Fixes failing Dependabot PRs, remediates remaining vulnerability/code/ secret alerts, and submits PRs for manual review.
How this skill is triggered — by the user, by Claude, or both
Slash command
/resolve-github-alerts:resolve-github-alertsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill resolves all GitHub security alerts: Dependabot alerts,
This skill resolves all GitHub security alerts: Dependabot alerts, code scanning alerts, and secret scanning alerts.
automated/resolve-github-alertsautomated/resolve-github-alertsmain. Most
repos use main, but some use master, develop, or trunk. Run
gh repo view --json defaultBranchRef --jq .defaultBranchRef.name
once at the start of execution and use the result everywhere a base
branch is needed (PR creation, branch creation, etc.).At the start of execution, derive the GitHub owner and repo. Use
git remote get-url origin from the current working directory
(works in both the main checkout and git worktrees):
OWNER_REPO=$(git remote get-url origin | sed -E 's#.*(github\.com[:/])##;s/\.git$//')
OWNER=${OWNER_REPO%/*}
REPO=${OWNER_REPO#*/}
Use $OWNER and $REPO in all gh CLI commands below.
This skill may run inside a git worktree. Observe these rules:
git rev-parse --show-toplevel, never
hard-code a path.git remote, git fetch, git push, and gh commands work
unchanged in a worktree because they share the main repo's
remote configuration.git worktree add/remove — the caller manages the
worktree lifecycle.requirements*.{in,txt}, pyproject.toml, poetry.lock,
uv.lock, package.json, Cargo.toml, go.mod), Dockerfile base
image tags, GitHub Actions versions, or application code fixes in
the project's source tree. Never apply ad hoc fixes via manual
steps. Never add lint exclusions or scanner ignores.Maintain at most ONE open PR at a time for non-Dependabot fixes.
Identified by the automated/resolve-github-alerts label.
Search for an existing open PR:
gh pr list --repo $OWNER/$REPO --label automated/resolve-github-alerts --state open --json number,title
If PR exists: Push additional commits to the existing
automated/resolve-github-alerts branch and update the PR body.
If no PR exists: Create the branch from main, push fixes,
create the PR, and add labels/assignee:
automated/resolve-github-alerts, security, dependencies$OWNERRun all four phases in order. Track results for the final summary.
Goal: List open Dependabot PRs, check CI status, and fix ones with CI failures if possible. Never auto-merge — leave merging to the user.
gh pr list --repo $OWNER/$REPO --state open --author "app/dependabot" --json number,title,headRefName
For each Dependabot PR, check CI status:
gh pr checks <PR_NUMBER> --repo $OWNER/$REPO
Categorize each PR:
For each failing Dependabot PR:
Get the PR diff to understand the dependency change:
gh pr diff <PR_NUMBER> --repo $OWNER/$REPO
Get the failure details from the checks output.
Determine if the failure is fixable:
After pushing fixes, re-check CI status and report result.
Track counts: passing (ready to merge), fixed (ready to merge), attempted fix (still failing), pending, skipped.
Goal: Resolve open Dependabot vulnerability alerts that don't have associated PRs.
gh api repos/$OWNER/$REPO/dependabot/alerts --jq '[.[] | select(.state == "open")] | length'
Get full alert details:
gh api repos/$OWNER/$REPO/dependabot/alerts \
--jq '[.[] | select(.state == "open")] | .[] | {
number, state,
dependency: .dependency.package.name,
ecosystem: .dependency.package.ecosystem,
manifest: .dependency.manifest_path,
severity: .security_advisory.severity,
summary: .security_advisory.summary,
fixed_in: .security_vulnerability.first_patched_version.identifier
}'
If no open alerts, skip to Phase 3.
Each Dependabot alert payload includes a dependency.manifest_path
field — that's the ground-truth file holding the vulnerable pin.
Always prefer manifest_path over guesswork. The discovery globs
below are only for finding related files (e.g. when a
requirements.in change cascades into a requirements.txt regen, or
when a package.json bump must update its lockfile).
Map by dependency.package.ecosystem:
| Alert ecosystem | Discovery globs (related files) |
|---|---|
pip | requirements*.{in,txt}, pyproject.toml, setup.py, setup.cfg, Pipfile{,.lock}, poetry.lock, uv.lock |
npm | package.json, package-lock.json, yarn.lock, pnpm-lock.yaml |
cargo | Cargo.toml, Cargo.lock |
go | go.mod, go.sum |
composer | composer.json, composer.lock |
bundler | Gemfile, Gemfile.lock |
nuget | *.csproj, packages.config, *.props |
docker | **/Dockerfile* |
github-actions | .github/workflows/*.{yml,yaml} |
If the ecosystem isn't in the table, fall back to reading
dependency.manifest_path and applying the smallest possible edit
that bumps the pin — most ecosystems use a "manifest + lockfile" pair
that's straightforward to update once you've read both.
For each alert:
Read the file at dependency.manifest_path to confirm the current
pin.
Determine the fix command by dependency.package.ecosystem:
pip with pip-tools (detect: any requirements*.in exists
alongside its .txt): bump the version pin in the matching .in
file. Recompile via the project's lockfile command (see
Step 2.4).pip without pip-tools (no .in files): bump the pin
directly in requirements.txt / pyproject.toml's
[project] dependencies / setup.py install_requires.pip with poetry (detect: pyproject.toml [tool.poetry]
with poetry.lock): poetry add <pkg>@<version>, then
poetry lock --no-update.pip with uv (detect: uv.lock): edit the dep in
pyproject.toml (or run uv pip install <pkg>==<version>),
then uv lock --upgrade-package <pkg>.npm (detect: package-lock.json): bump in package.json,
then npm install <pkg>@<version> (regenerates the lockfile).yarn (detect: yarn.lock): yarn add <pkg>@<version>.pnpm (detect: pnpm-lock.yaml): pnpm add <pkg>@<version>.cargo: bump in Cargo.toml, then
cargo update -p <pkg> --precise <version>.go: go get <module>@<version> && go mod tidy.docker: update the image tag in the Dockerfile at
manifest_path. Prefer immutable tags (digest pinning with
@sha256:...) when the original used digest pinning.github-actions: update the action version in the workflow
at manifest_path. Prefer SHA + comment pinning (e.g.
uses: actions/checkout@<sha> # v5.0.1) when the rest of the
repo follows that style.Apply edits via the Edit tool. For commands that mutate lockfiles, run them in the worktree root.
After applying fixes, run the project's verify commands. Detect them in this order — first match wins:
Recompile lockfile (only when applicable):
Makefile defines compile-requirements, lock, or
update-deps → make <target>.requirements*.in exists →
pip-compile --generate-hashes <input>.in for each.poetry.lock exists → poetry lock --no-update.uv.lock exists → uv lock.Lint:
Makefile defines lint → make lint..pre-commit-config.yaml exists →
pre-commit run --all-files.ruff check . if available.npm run lint if package.json has a lint
script.Test:
Makefile defines test → make test.pytest if available.npm test if package.json has a test
script.A missing lint/test step is not a hard failure for opening the PR — note it in the PR body so the human reviewer knows what wasn't auto-verified.
Follow the PR Management Pattern above. Commit all Dependabot alert fixes together with a clear message describing what was bumped and why.
Goal: Fix SAST/code scanning findings in source code.
gh api repos/$OWNER/$REPO/code-scanning/alerts --jq '[.[] | select(.state == "open")] | length'
Get full alert details:
gh api repos/$OWNER/$REPO/code-scanning/alerts \
--jq '[.[] | select(.state == "open")] | .[] | {
number, state,
rule: .rule.id,
severity: .rule.severity,
description: .rule.description,
path: .most_recent_instance.location.path,
start_line: .most_recent_instance.location.start_line,
end_line: .most_recent_instance.location.end_line
}'
If no open alerts, skip to Phase 4.
Read the affected source file at the identified line range to understand the context and determine the correct fix.
Apply the appropriate fix based on the alert type:
| Alert Type | Fix Pattern |
|---|---|
| SQL injection | Use parameterized queries |
| Command injection | Use subprocess.run() with list args, never shell=True with user input |
| Path traversal | Validate and sanitize paths, use os.path.realpath() + prefix check |
| XSS | Escape output, use safe templating |
| Insecure deserialization | Replace pickle.loads with JSON or safe alternatives |
| Hardcoded credentials | Move to environment variables |
| Weak cryptography | Upgrade to strong algorithms (AES-256, SHA-256+) |
Apply fixes using the Edit tool.
Add code scanning fixes to the same PR branch (following PR Management Pattern). If no PR exists yet, create one.
Goal: Handle exposed secrets detected by GitHub secret scanning.
gh api repos/$OWNER/$REPO/secret-scanning/alerts --jq '[.[] | select(.state == "open")] | length'
If no open alerts, skip to Summary.
gh api repos/$OWNER/$REPO/secret-scanning/alerts \
--jq '[.[] | select(.state == "open")] | .[] | {
number, state,
secret_type: .secret_type_display_name,
created_at
}'
For false positives (test keys, example values, already-rotated secrets):
For real credentials:
[Secret Scanning] Rotate exposed <secret_type>security, automated/resolve-github-alerts$OWNER.gitignore if it's a credentials fileAfter all phases complete, output a summary table:
## Security Alert Resolution Summary
### Phase 1: Dependabot PRs
| PR | Title | CI Status | Action |
| ---- | ------- | ---------- | -------- |
| #XX | Bump foo from 1.0 to 1.1 | Passing | Ready to merge |
| #YY | Bump bar from 2.0 to 2.1 | Fixed | Ready to merge |
### Phase 2: Dependabot Alerts
| Alert | Package | Severity | Action | Result |
| ------- | --------- | ---------- | -------- | -------- |
| #NN | package-name | high | Version bump | Fixed in PR #ZZ |
### Phase 3: Code Scanning Alerts
| Alert | Rule | File | Action | Result |
| ------- | ------ | ------ | -------- | -------- |
| #NN | rule-id | src/file.py | Fixed pattern | Fixed in PR #ZZ |
### Phase 4: Secret Scanning Alerts
| Alert | Type | Action | Result |
| ------- | ------ | -------- | -------- |
| #NN | secret-type | False positive | Noted for manual review |
### Totals
- Dependabot PRs ready to merge: X
- Dependabot alerts fixed: X
- Code scanning alerts fixed: X
- Secret scanning alerts handled: X
- Items requiring manual attention: X
If no issues were found across all phases, report:
## All Clear
No open security alerts found.
- Dependabot PRs checked: 0 open
- Dependabot alerts: 0 open
- Code scanning alerts: 0 open
- Secret scanning alerts: 0 open
End the summary with: Generated by /resolve-github-alerts
When creating or updating the fix PR, use this format:
Title: fix: resolve GitHub security alerts
Body:
## Summary
Automated resolution of GitHub security alerts.
<insert summary table from above>
## Changes
<bulleted list of specific changes made>
## Test Plan
- [ ] CI checks pass
- [ ] No new security alerts introduced
- [ ] Dependency compatibility verified
Generated by `/resolve-github-alerts`
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub taylorleese/mcp-toolz --plugin resolve-github-alerts