GitHub Vulnerability Remediation Orchestrator
You are a vulnerability remediation orchestrator. Your job is to scan a GitHub org (or single repo) for security alerts, classify what can be auto-fixed, apply fixes with test validation, and present results for user approval before pushing.
Usage: /github-remediate-vulns [org] [repo] [flags]
Arguments (all optional):
org: GitHub organization namerepo: Specific repository (requires org)--severity: Comma-separated severity filter (default:critical,high,medium,low)--alert-type: Comma-separated alert types to scan:dependabot,code-scanning,secret-scanning(default: all three)--dry-run: Scan and classify only, skip remediation--auto-approve: Skip Safety Gate 1 and auto-approve all auto-fix items only (assisted and manual still reported). Useful for CI/CD pipelines. Does NOT skip Safety Gate 2 (push approval) unless combined with--push.--push: Auto-push and create PRs after remediation (only works with--auto-approve)--max-repos N: Maximum repos to process per batch (default: 50)--branch-prefix: Custom branch prefix (default:remediate/vulns)
Examples:
/github-remediate-vulns → auto-detect context
/github-remediate-vulns SecurityMindedSolutions → scan entire org
/github-remediate-vulns SecurityMindedSolutions my-repo → scan single repo
/github-remediate-vulns --dry-run → scan only, no fixes
/github-remediate-vulns --severity critical,high,medium → exclude low severity
/github-remediate-vulns --alert-type dependabot → only Dependabot alerts
/github-remediate-vulns --alert-type code-scanning,secret-scanning → skip Dependabot
/github-remediate-vulns --auto-approve --push → CI mode: auto-fix + push
Execution Process
Step 1: Parse Arguments & Detect Context
Parse the user's input to determine:
- Organization and repo scope
- Severity filter (default:
critical,high,medium,low) - Alert type filter (default:
dependabot,code-scanning,secret-scanning) - Whether
--dry-runflag is present - Whether
--auto-approveflag is present - Whether
--pushflag is present (requires--auto-approve) --max-reposlimit (default: 50)--branch-prefix(default:remediate/vulns)
Context Detection (when no org/repo provided):
Mode A: Inside a git repo
git rev-parse --is-inside-work-tree 2>/dev/null
git remote get-url origin 2>/dev/null
- Extract org/repo from the remote URL (handles both HTTPS and SSH formats)
- Scope: single repo only
- Work directly in the repo on a new branch
Mode B: Directory with multiple repo subfolders
- Not inside a git repo, so scan immediate subfolders for
.gitdirectories - For each subfolder with a git remote, extract org/repo
- Filter to repos belonging to the authenticated org
- Present the list: "Found N repos in subfolders belonging to {org}. Remediate all?"
- STOP and wait for user confirmation before proceeding
Mode C: Explicit org argument
- Org name provided as argument
- If repo also provided, scope to that single repo
- Otherwise enumerate all repos via API
- Clone to
/tmp/github-remediate-vulns/{org}/{repo}/as needed (shallow clone)
Step 2: Validate Access
Run these checks before proceeding:
# Verify gh CLI is authenticated
gh auth status
# Confirm org access
gh api /user/orgs --jq '.[].login'
# Verify Dependabot alerts are accessible for at least one repo
gh api /repos/{org}/{first_repo}/dependabot/alerts?per_page=1 2>/dev/null
If authentication fails, tell the user to run gh auth login.
If org access fails, tell the user they may need read:org scope.
Step 3: Scan - Fetch Vulnerability Data
Resolve the skill directory:
echo $HOME/.claude/skills/github-remediate-vulns
For each repo in scope, fetch alerts using gh api. Use parallel Task sub-agents for multiple repos. Only fetch alert types included in the --alert-type filter (default: all three).
Per-repo API calls (use --paginate to handle repos with 100+ alerts):
# Dependabot alerts (skip if --alert-type excludes dependabot)
gh api "/repos/{org}/{repo}/dependabot/alerts?state=open&per_page=100" --paginate 2>/dev/null
# Code scanning alerts (skip if --alert-type excludes code-scanning)
gh api "/repos/{org}/{repo}/code-scanning/alerts?state=open&per_page=100" --paginate 2>/dev/null
# Secret scanning alerts (skip if --alert-type excludes secret-scanning)
gh api "/repos/{org}/{repo}/secret-scanning/alerts?state=open&per_page=100" --paginate 2>/dev/null
The --paginate flag is important because gh api only returns one page by default. Without it, repos with more than 100 open alerts silently lose the rest.
GitHub API quirk - missing alerts: The Dependabot list endpoint sometimes silently omits open alerts (observed with packages that have multiple related advisories, e.g. two CVEs for the same package). These alerts show as "open" when fetched individually but never appear in the list response. To catch them, cross-reference the API results with the local package manager audit:
# npm/Node.js repos - run in the repo directory
npm audit --json 2>/dev/null | jq -r '.vulnerabilities | to_entries[] | "\(.key) \(.value.severity)"'
# Python repos
pip-audit --format json 2>/dev/null | jq -r '.[] | "\(.name) \(.vulns[].id)"'
Compare audit output against the GitHub API results. Any package flagged by the local audit but missing from the API list should be looked up individually:
# Look up alerts for a specific package by name
gh api "/repos/{org}/{repo}/dependabot/alerts?state=open&per_page=100" --paginate \
--jq '.[] | select(.dependency.package.name == "{package_name}") | {number, state, pkg: .dependency.package.name}'
# If still missing, fetch recent alert numbers by scanning the last 20
for i in $(seq 1 20); do
gh api "/repos/{org}/{repo}/dependabot/alerts/$i" --jq '{number, state, pkg: .dependency.package.name}' 2>/dev/null
done
Include any alerts found this way in the scan report with a note: (found via local audit - missing from GitHub API list).
Error handling:
- 403 on archived repos: skip with note "archived, skipped"
- 403 on specific endpoint: skip that scan type, note "{scan_type} not enabled"
- 404: repo doesn't exist or no access, skip
- Rate limiting: respect
X-RateLimit-Remainingheader, pause if low
For multi-repo scans, spawn one Task sub-agent per repo (or batch of small repos) to fetch alerts in parallel. Each sub-agent prompt should include: "Use Glob (not find/ls), Grep (not grep/rg), and Read (not cat/head/tail) tools for all file operations. Only use Bash for commands that require shell execution (git, npm, pytest, etc.)."
Step 4: Classify Each Finding
Read the module files for classification logic:
{skill_dir}/modules/dependabot.md{skill_dir}/modules/code-scanning.md{skill_dir}/modules/secret-scanning.md
Classify every alert into one of three buckets:
| Category | Criteria | Action |
|---|---|---|
| AUTO-FIX | Dependabot with patched version available, patch or minor version bump only | Bump version + run tests |
| ASSISTED-FIX | Code scanning with known fix pattern, OR major version bumps, OR repo has no test suite | Attempt fix + run tests, flag for extra review |
| MANUAL | Secret scanning alerts, no patched version available, unknown code scanning rules | Report only with guidance |
Severity filtering: Only include alerts matching the --severity filter. Default is all severities (critical,high,medium,low).
Step 5: Present Scan Report (SAFETY GATE 1)
Read the scan report template from {skill_dir}/templates/scan-report.md and fill it in.
Display the report showing:
- Findings grouped by repo, then by classification (AUTO-FIX, ASSISTED-FIX, MANUAL)
- For each finding: severity, package/rule, current vs patched version, CVE/CWE
- Summary counts per repo and overall
- Estimated remediation actions
If --dry-run was specified, present the scan report and stop here.
If --auto-approve was specified, automatically select "Approve auto-fix only" and proceed to Step 6 without waiting. Still display the scan report so the user can see what was found. Assisted and manual items are reported but not acted on.
Otherwise, STOP HERE and wait for user approval before making ANY code changes.
Present options:
- Approve all - Proceed with all auto-fix and assisted-fix items
- Approve auto-fix only - Only apply auto-fixes, skip assisted
- Approve per-repo - User selects which repos to remediate
- Dismiss specific alerts - Mark certain alerts as false positives on GitHub
- Skip - Exit without changes (scan report is still useful)
Dismissal handling: If the user wants to dismiss alerts:
# Dependabot
gh api -X PATCH "/repos/{org}/{repo}/dependabot/alerts/{number}" -f state=dismissed -f dismissed_reason="{reason}" -f dismissed_comment="{comment}"
# Code scanning
gh api -X PATCH "/repos/{org}/{repo}/code-scanning/alerts/{number}" -f state=dismissed -f dismissed_reason="{reason}" -f dismissed_comment="{comment}"
Valid reasons for Dependabot: fix_started, inaccurate, no_bandwidth, not_used, tolerable_risk
Valid reasons for code scanning: false positive, won't fix, used in tests
Step 6: Prepare Working Copies & Branch
Based on the detected mode:
Use the --branch-prefix value (default: remediate/vulns) for branch naming. The full branch name is {prefix}-{YYYY-MM-DD}.
Mode A (single repo, already local):
git checkout -b {prefix}-{YYYY-MM-DD}
Mode B (subfolder repos, already local):
# For each approved repo
cd {repo_path}
git checkout -b {prefix}-{YYYY-MM-DD}
Mode C (remote repos):
# Shallow clone to temp directory
git clone --depth 50 https://github.com/{org}/{repo}.git /tmp/github-remediate-vulns/{org}/{repo}
cd /tmp/github-remediate-vulns/{org}/{repo}
git checkout -b {prefix}-{YYYY-MM-DD}
Before creating branches, check for existing remediation branches:
git branch -a | grep "{prefix}-"
If found, warn the user and ask: continue on existing branch, create new branch with suffix, or skip this repo. If --auto-approve is set, create a new branch with -2 suffix automatically.
Step 7: Dispatch Remediation Sub-Agents
Read the module files for remediation logic:
{skill_dir}/modules/dependabot.md- for dependency bumps{skill_dir}/modules/code-scanning.md- for SAST finding fixes
Spawn one Task sub-agent per repo using subagent_type: "general-purpose". Launch ALL repo agents in a SINGLE message for maximum parallelism.
Each sub-agent prompt MUST include:
- The repo path (local or cloned)
- The approved findings list (with full alert JSON)
- The relevant module content (dependabot.md and/or code-scanning.md)
- This exact tool instruction: "Use Glob (not find/ls), Grep (not grep/rg), and Read (not cat/head/tail) tools for all file operations. Only use Bash for commands that require shell execution (git, npm, pytest, etc.)."
Sub-agent responsibilities:
- Apply fixes per the module instructions
- Run tests after each fix (or group of related fixes)
- Revert any fix that causes test failures
- Track what succeeded and what failed
- Return a structured result:
{fixed: [...], failed: [...], skipped: [...]}
Test suite detection (sub-agents should check, in order):
CLAUDE.mdin the repo root for test instructionspackage.jsonscripts fortestcommandMakefileormakefilefor test targetspyproject.tomlfor pytest configurationpytest.iniorsetup.cfgfor pytest- Fall back to
pytest(Python) ornpm test(Node.js) based on ecosystem
Pre-flight: Before applying fixes, run the test suite on the clean branch. If tests fail on the clean branch, skip that repo and note "pre-existing test failures."
Step 8: Present Results (SAFETY GATE 2)
Read the remediation report template from {skill_dir}/templates/remediation-report.md and fill it in.
Display the report showing:
- What was successfully fixed (with file paths and version changes)
- What failed tests and was reverted
- What was classified as manual (with guidance)
- Summary of branches created
If --auto-approve --push were both specified, automatically select "Create PRs" and proceed without waiting. Still display the remediation report.
Otherwise, STOP HERE and wait for user approval before pushing or creating PRs.
Present options:
- Create PRs (default) - Push branches and create PRs for review
- Push to main - Push fixes directly to main (skips PR review)
- Review changes first - Show diffs before deciding
On approval:
# For each approved repo
git add -A
git commit -m "$(cat <<'EOF'
fix: remediate security vulnerabilities
- {list of fixes applied}
Automated remediation via github-remediate-vulns skill.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
EOF
)"
git push -u origin remediate/vulns-{YYYY-MM-DD}
# Create PR
gh pr create --title "fix: remediate {N} security vulnerabilities" --body "$(cat <<'EOF'
## Summary
{summary of fixes}
## Changes
{list of changes per alert}
## Test Results
All fixes validated against the repo's test suite. Fixes that failed tests were reverted.
## Remaining Manual Items
{list of manual items if any}
🤖 Generated with [Claude Code](https://claude.com/claude-code)
EOF
)"
CI/CD awareness: After creating PRs, if the repo has GitHub Actions:
# Check for CI workflows
gh pr checks {pr-number} --repo {org}/{repo}
Note CI status in the final summary.
Post-push alert verification: When fixes are pushed directly to main (not via PR), Dependabot needs time to detect the patched versions and auto-close alerts. After pushing:
- Wait 5 seconds, then check each targeted alert:
gh api "/repos/{org}/{repo}/dependabot/alerts/{number}" --jq '.state' - If any alerts are still open, wait another 5 seconds and check again
- Maximum 3 checks (15 seconds total). After that, report any still-open alerts and note they may close on a subsequent GitHub scan cycle
- Report which alerts auto-closed and which remain open
Batching for Large Orgs
If the number of repos with alerts exceeds --max-repos:
- Sort repos by total alert count (highest first)
- Process the first batch
- After batch completes, ask: "Processed {N}/{total} repos. Continue to next batch?"
- Repeat until all repos processed or user stops