Skip to content

Instantly share code, notes, and snippets.

@alexlib
Last active May 15, 2026 20:41
Show Gist options
  • Select an option

  • Save alexlib/dc8bafa8224887633c300e282491eb61 to your computer and use it in GitHub Desktop.

Select an option

Save alexlib/dc8bafa8224887633c300e282491eb61 to your computer and use it in GitHub Desktop.
Claude Code skill: fix-vulnerabilities — scan GitHub repos for Dependabot alerts and auto-fix vulnerable Python dependencies
name fix-vulnerabilities
description Scan GitHub repos for Dependabot security alerts and auto-fix vulnerable Python dependencies. Use this skill whenever the user mentions vulnerability scanning, Dependabot alerts, dependency security, fixing CVEs, patching packages, keeping repos healthy, or cleaning up security warnings on GitHub. Also trigger when the user asks to check security across their repos, update insecure packages, or fix GitHub security alerts. Works on the current repo or all repos under a GitHub user/org.

Fix Vulnerabilities

Scan GitHub repositories for open Dependabot security alerts, update the vulnerable Python packages in dependency files, commit, and push — all automatically.

Installation

  1. Download this file and place it at:

    ~/.claude/skills/fix-vulnerabilities/SKILL.md
    

    Quick setup:

    mkdir -p ~/.claude/skills/fix-vulnerabilities
    curl -o ~/.claude/skills/fix-vulnerabilities/SKILL.md \
      https://gist.githubusercontent.com/alexlib/dc8bafa8224887633c300e282491eb61/raw/SKILL.md
  2. Restart Claude Code. The skill will appear in the available skills list automatically.

Usage

Single repo — cd into any git repo and type:

/fix-vulnerabilities

Or just ask naturally: "check this repo for vulnerabilities and fix them"

Multi-repo — scan all repos under a GitHub user or org:

scan all repos under myusername for vulnerabilities and fix them

Or casually: "my github repos have dependabot warnings, clean them up"

Prerequisites

  • gh CLI authenticated (gh auth status should succeed)
  • Git configured with push access to target repos
  • The repo must have Dependabot alerts enabled on GitHub

Modes

Single-repo mode (default)

When invoked inside a git repo with no arguments, fix vulnerabilities in the current repo.

Multi-repo mode

When the user provides a GitHub username or org name, scan all their public repos (or repos accessible to the authenticated user) and fix each one.

Workflow

Step 1: Identify target repos

Single-repo: Use gh repo view --json nameWithOwner to get the current repo.

Multi-repo: Use gh repo list <owner> --limit 200 --json nameWithOwner,name --no-archived to get all non-archived repos. For each repo, check if it has open Dependabot alerts before cloning.

Step 2: Check Dependabot alerts

Fetch ALL alerts (not just open ones) because GitHub sometimes marks alerts as "fixed" even when the dependency file hasn't actually been updated. This catches stale fixes.

gh api repos/{owner}/{repo}/dependabot/alerts \
  --jq '.[] | {
    number: .number,
    state: .state,
    package: .security_vulnerability.package.name,
    ecosystem: .security_vulnerability.package.ecosystem,
    severity: .security_advisory.severity,
    summary: .security_advisory.summary,
    vulnerable_range: .security_vulnerability.vulnerable_version_range,
    patched: .security_vulnerability.first_patched_version.identifier
  }'

If the API returns a 403 or empty result, skip the repo — Dependabot may not be enabled.

Filter to ecosystem == "pip" since we handle Python dependencies only. Count alerts for other ecosystems (npm, rubygems, actions, etc.) and report them in the summary so the user knows what needs manual attention, but don't attempt those fixes.

Step 3: Find and read dependency files

Look for these files in the repo root (and common subdirectories):

  1. requirements.txt (and variants like requirements-dev.txt, requirements/*.txt)
  2. pyproject.toml (look in [project.dependencies] and [project.optional-dependencies])
  3. setup.cfg (look in [options] install_requires)
  4. setup.py (look in install_requires list)

Step 4: Verify and update vulnerable packages

This is the critical step. For EVERY alert (open AND "fixed"), cross-check the version currently pinned in the dependency file against the patched version. GitHub's "fixed" state can be wrong — the alert may show as fixed while the dependency file still pins a vulnerable version.

For each alert that has a patched version:

  1. Find the package in the dependency file(s)
  2. Parse the currently pinned version
  3. Compare it to the patched version — if the pinned version is LOWER than the patched version, it needs updating regardless of the alert's state
  4. Update the pinned version:
    • package==1.2.3package==<patched>
    • package>=1.2.3package>=<patched>
    • package~=1.2.3package~=<patched>
    • For unpinned deps (package with no version), add >=<patched>

Handle case-insensitive package name matching — pip treats _ and - as equivalent, so jupyter-server matches jupyter_server.

If a package appears in the alerts but NOT in any dependency file, it's likely a transitive dependency. Note it for the user but don't create new entries — the fix needs to come from updating the direct dependency that pulls it in.

Classify each alert into one of these categories for the summary:

  • Auto-fixable: package is in a dep file and has a patched version
  • No patch available: Dependabot hasn't identified a safe version yet
  • Transitive: vulnerable package isn't a direct dependency
  • Non-Python: npm, actions, rubygems, etc. — reported but not fixed

Step 5: Present a summary table

Before committing, show the user what changed:

| Package        | Old Version | New Version | Alerts Fixed | Severity    |
|----------------|-------------|-------------|--------------|-------------|
| urllib3        | 2.6.3       | 2.7.0       | 2            | 2 High      |
| jupyter-server | 2.15.0      | 2.18.0      | 4            | 3 High, 1 Med |

Also list any alerts that couldn't be auto-fixed (no patched version, transitive dep, non-Python ecosystem) so the user knows what needs manual attention.

Step 6: Commit and push

Create a single commit with a descriptive message:

Bump <packages> to fix security vulnerabilities

- package1 X.Y.Z → A.B.C (summary of vuln)
- package2 X.Y.Z → A.B.C (summary of vuln)

Fixes N open Dependabot alerts.

Push to the current branch (typically main). Include a Co-Authored-By trailer.

Multi-repo: Clone, fix, push, clean up

For multi-repo mode, for each repo with alerts:

  1. Clone into a temp directory: gh repo clone {owner}/{repo} /tmp/fix-vuln-{repo}
  2. Run the single-repo workflow inside that clone
  3. Push changes
  4. Remove the temp clone
  5. Move to the next repo

At the end, show a summary of all repos processed with ecosystem breakdown:

| Repo           | Total | pip | npm | actions | Auto-Fixed | Remaining        | Status   |
|----------------|-------|-----|-----|---------|-----------|------------------|----------|
| owner/repo-a   | 5     | 5   | 0   | 0       | 5         | 0                | Clean    |
| owner/repo-b   | 15    | 10  | 5   | 0       | 8         | 7 (2 no patch, 5 npm) | Partial  |
| owner/repo-c   | 0     | 0   | 0   | 0       | 0         | 0                | Already clean |

Also include a priority ordering of repos by risk (critical alerts first, then high count).

Error handling

  • If gh auth status fails, tell the user to run gh auth login first
  • If a repo has no dependency files, skip it and note it in the summary
  • If git push fails (permissions, branch protection), report the error and continue to the next repo
  • If the Dependabot API returns rate-limit errors, wait and retry with exponential backoff

What this skill does NOT do

  • Fix non-Python vulnerabilities (it reports them but doesn't patch JS/Ruby/Go/etc.)
  • Run tests after updating — the user should verify compatibility
  • Create pull requests — it pushes directly (if the user wants PRs instead, they should say so)
  • Handle major version bumps that might break APIs — it patches to the minimum safe version reported by Dependabot
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment