Patchbot

Patchbot is an open-source vulnerability scanner that fixes what it finds. It inventories your dependencies, matches them against OSV.dev or your own threat feed, takes findings from any scanner, and opens a pull request per vulnerable package - bumping the version when that is enough and handing the failure to a coding agent when it is not.

Patchbot finds five lodash advisories, fixes them, and re-scans clean

How it works

Every run builds one inventory, matches it against your feeds and scanners, and deduplicates the findings. From there it either prints a report (table, JSON or SARIF) or runs the fix loop.

Inventory

NPMPyPIGoRust

Reads npm, pnpm and yarn lockfiles, requirements*.txt, pyproject.toml, go.mod and Cargo.toml. Anything else comes in as a CycloneDX SBOM.

Feeds

OSV.dev is on by default. Add a private feed by serving OSV-schema JSON from a file or URL.

Scanners

Trivy

Wrappers for trivy, grype and osv-scanner, plus a command scanner for any tool that prints SARIF, Trivy, Grype or osv-scanner JSON.

Fix

Claude CodeCodexOpenAI

Bump, verify, escalate to an agent if the build breaks, verify again, then open the PR with the advisory table in its body.

The fix loop works one branch per vulnerable package. It rewrites the pin to the lowest version that clears every advisory and regenerates the lockfile with the ecosystem's own tool - no model call. It then re-scans, runs your test_cmd, and rejects any diff that reaches outside the dependency surface. Only if that fails does it brief the agent with the failure itself, and it verifies again before it commits. --agent none keeps it bump-only.

Install

Requires Python 3.11 or newer.

pip install patchbot            # scan + bump-only fixes
pip install "patchbot[api]"     # + Anthropic-backed agent tiers (api, managed)
pip install "patchbot[openai]"  # + OpenAI Agents API tier (openai)

Quick start

patchbot scan                    # inventory -> OSV.dev -> table report
patchbot fix --dry-run           # preview the fix plan, change nothing
patchbot fix --pr                # bump or fix, verify, open one PR per package

scan exits 1 when any finding meets --fail-on (default high), so it can gate a build on its own.

patchbot scan listing five lodash advisories

A dry run shows the plan - which pin moves where - before anything is written:

patchbot fix --dry-run showing the planned lodash bump

Configure it

Put patchbot.toml in the repository root. CLI flags override the file. Every section is optional; with no file at all you get OSV.dev and a bump-only fix loop.

[inventory]
paths = ["."]
# sbom = "sbom.cdx.json"        # CycloneDX, for full Python / Go / Rust trees

[feeds.osv]
enabled = true

[feeds.internal]                # your own threat feed
type = "url"                    # or "file" with path = "..."
url  = "https://intel.example.com/advisories.json"

[scanners.trivy]
enabled = true

[scanners.custom]               # your own scanner
type   = "command"
cmd    = "./scan.sh"
format = "sarif"                # sarif | trivy | grype | osv-scanner

[report]
fail_on = "high"                # critical | high | medium | low | none
ignore  = ["GHSA-xxxx-xxxx-xxxx"]

[fix]
agent    = "claude"             # claude | codex | api | openai | command | managed | none
max_prs  = 5
test_cmd = "npm test"

patchbot plugins lists every feed, scanner and agent it can see, including ones your own packages register through entry points.

patchbot plugins listing feeds, scanners and agents

Choose an agent backend

The agent only runs when a bump breaks the build. Pick where it runs with [fix] agent or --agent.

BackendRuns whereNeedsUse it for
Claude CodeCodexclaude / codexYour machine or runner, through the CLI on PATHThe CLI, logged inLocal development
AnthropicapiYour runner, in processpatchbot[api], ANTHROPIC_API_KEYCI without Node
OpenAIopenaiYour runner, in processpatchbot[openai], OPENAI_API_KEYCI without Node, on OpenAI models
AgentcommandWherever your tool runsAny agent that takes a prompt (aider, opencode, ...)Other models
Claude AImanagedAnthropic's sandbox, off your runnerpatchbot managed init once, three IDs as secretsCI where the agent must not see repo secrets

Use managed in CI. An agent with a shell on your runner sits next to your repository secrets. The managed backend moves it into a Claude Managed Agents sandbox: Anthropic's git proxy authenticates the push and a vaulted GitHub credential opens the PR, so your GitHub token never enters the sandbox. Patchbot re-scans the pushed branch on your side before it counts the fix as done.

pip install "patchbot[api]"
patchbot managed init --github-mcp-token "$GITHUB_MCP_TOKEN"
# prints agent_id, environment_id, vault_id - store them as repo secrets
patchbot fix --agent managed --pr

GitHub Actions Run it in GitHub Actions

Scan on every push and publish the results to the repository's Security tab:

permissions:
  security-events: write
steps:
  - uses: actions/checkout@v4
  - uses: PrismorSec/patchbot@v0
    with:
      fail-on: high
GitHub code scanning alerts detected by patchbot

Add auto-fix with the managed backend - no Node, and no agent on the runner:

permissions:
  contents: write
  pull-requests: write
steps:
  - uses: actions/checkout@v4
  - uses: PrismorSec/patchbot@v0
    with:
      fix: "true"
      agent: managed
      managed-agent-id: ${{ secrets.PATCHBOT_AGENT_ID }}
      managed-environment-id: ${{ secrets.PATCHBOT_ENVIRONMENT_ID }}
      managed-vault-id: ${{ secrets.PATCHBOT_VAULT_ID }}
    env:
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Each fix lands as its own pull request, with the advisories it clears and which tier fixed it:

A pull request opened by patchbot that bumps lodash to 4.18.0

For a weekly run against a private feed, put the cron on the workflow and point the action at your config with config: patchbot.toml. The repository's action.yml documents every input.

Run it on a schedule, without CI GitHubGitLabBitbucket

patchbot managed deploy creates a cron-scheduled Managed Agents session that clones your repositories, scans, fixes and opens pull requests. Nothing in it depends on GitHub Actions, so it works for GitLab and Bitbucket repositories too.

patchbot managed deploy \
  --repos owner/api,owner/web \
  --cron "0 6 * * *" --tz UTC \
  --agent-id agent_... --environment-id env_... --vault-id vlt_... \
  --run-now                       # fire one session now to test

Manage it with patchbot managed list | pause | unpause. Scheduled runs are jittered by up to nine minutes, and 1-3 AM local times can skip or double-fire across DST changes, so schedule outside that window or use UTC.

Frequently asked questions

Why did a fix report failed?

Patchbot prints the reason: the advisory still reproduces after the bump or the agent run, test_cmd failed (with the log tail), or the change touched files outside the dependency surface. It discards the branch and commits nothing.

How do I suppress one advisory?

Add its ID to [report] ignore in patchbot.toml, for example ignore = ["GHSA-..."].

Do I need Node in CI?

Only for the claude or codex agent backends. The api, openai and managed backends need Python alone.

Which ecosystems include transitive dependencies?

npm, pnpm and yarn, through their lockfiles. For Python, Go and Rust, set [inventory] sbom to a CycloneDX file to scan the full resolved tree.