Patchhog
Try it for free
Patchhog · docs

Documentation

Everything Patchhog ships — six scanner suites, the dashboard workflows that consume their output, the integrations that push it back out, and the security model the whole thing runs on.

Quickstart

Connect a GitHub repository and Patchhog scans every push automatically. From first commit to a paste-ready fix usually takes under two minutes.

1. Connect a repo

Sign in with GitHub on the dashboard and authorize the OAuth app, then pick which repositories Patchhog should scan. The OAuth scope you grant at signup determines what Patchhog can do — including opening pull requests on your behalf.

2. Push a commit

Every push delivers a webhook to /api/webhooks/github. Patchhog verifies the HMAC signature, looks up the repo, and runs every scanner in parallel against the checkout. Pull-request events trigger an inline-comment decoration on the PR.

3. Review findings

Open the dashboard → Findings to see what the scan produced. Each finding carries the file, line, rule ID, severity, CWE mapping (where available), a code excerpt, and a paste-ready fix.

4. Ship the fix

For dependency CVEs with a known fixed version, click Fix and push on a scan and Patchhog commits straight to your default branch — bumping package.json ranges and regenerating the lockfile. For SAST, Secrets, IaC, and DAST findings, apply the recommended fix yourself and push.

Connect a repo

Patchhog installs as a GitHub OAuth app and a per-repo webhook. There is no GitHub App / Installation token in v1 — auth runs through your own OAuth token, which keeps the trust model simple and the audit trail clean.

What gets stored

  • Your github_access_token on the profiles row (so Patchhog can read code and open PRs)
  • One webhook_secret per repository, used to verify push / PR events with HMAC SHA-256
  • Repo metadata: owner, name, default branch, private flag, language

What Patchhog never gets

We don't mirror your source tree, don't cache it cross-repo, and don't share PATs between users. Each scan runs in an isolated worker that clones the repo, runs the scanners, normalizes findings, and discards the working copy.

Scanners — overview

Patchhog runs six scanner suites; four against your repository checkout, one against a configured live URL (DAST), and one against your seed domain's external attack surface (EASM). A seventh suite scans connected cloud accounts (AWS / GCP / Azure) when configured.

Where two scanners cover the same surface (Secrets, Dependencies), we keep both for higher recall and de-duplicate at the finding level using a stable fingerprint. Output is normalized into a small set of categories the dashboard understands: secret, sast, dependency, iac, dast, license, cloud.

Secrets

Runs the upstream gitleaks binary in detect mode against the working tree AND the last ~50 commits of git history — so secrets that were committed and later removed still get flagged.

trivy's secret scanner and Semgrep's p/secrets pack run alongside for triple-coverage of AWS / GCP / Stripe keys, GitHub tokens, OpenAI keys, JWTs, private SSH / PGP blocks, service-account JSON, and DB connection strings.

SAST

Runs the upstream semgrep binary with 14 curated rule packs:

  • Cross-cutting: p/security-audit, p/owasp-top-ten, p/cwe-top-25, p/secrets
  • Per-language: p/javascript, p/typescript, p/python, p/golang, p/java, p/ruby
  • Config files: p/dockerfile, p/docker-compose, p/kubernetes, p/terraform

Findings are CWE / OWASP mapped from Semgrep's rule metadata. Severity is taken from the rule's declared security-severity when present, otherwise mapped from INFO / WARNING / ERROR.

Dependencies

Runs Google's osv-scanner binary (which itself queries the OSV.dev database) against every lockfile it can find — package-lock.json, yarn.lock, pnpm-lock.yaml, Pipfile.lock, go.sum, Cargo.lock, Gemfile.lock.

trivy's vulnerability scanner runs in parallel for higher recall; the two streams are de-duplicated by canonical vuln ID (CVE or GHSA) and package coordinate. Each finding reports CVE, CVSS v3 score, CWE list, primary reference URL, and the fixed version range. This is the only category whose findings can be auto-PR'd — see Auto-PR for deps.

IaC

Runs the upstream trivy binary in fs --scanners misconfig mode. Covers Dockerfile, Kubernetes manifests, Terraform, and CloudFormation. Catches missing image pins, overly broad permissions, privileged containers, root-running pods, broken-by-default network policies, and similar configuration drift.

GitHub Actions workflows are not handled by Trivy — they're picked up by Semgrep's SAST packs (specifically p/security-audit and the language packs) instead.

DAST

Lightweight live-URL probes against a target URL you configure per repository under /dashboard/repositories/[id] → DAST target. Not OWASP ZAP — the scanner issues targeted HTTP requests for the issues that actually matter for most web apps, completing in a few seconds.

What it checks:

  • Security response headers (HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy)
  • Information leakage (Server, X-Powered-By, X-AspNet-Version banners; stack traces; source-map endpoints)
  • Commonly-exposed paths (.env, /admin, /backup.sql, /.git/config, ...)
  • Open-redirect parameters
  • TLS basics — HTTPS availability and HTTP → HTTPS regression
  • CORS configuration (wildcard with credentials)
  • robots.txt / sitemap.xml leakage of sensitive paths

EASM — External attack surface

From a single seed domain, Patchhog discovers up to 25 distinct hosts via certificate-transparency logs (crt.sh) and runs a head-of-page HEAD probe against each.

For every host it surfaces:

  • Missing / poor security headers
  • Server / framework banners that leak versions
  • HTTP-only services on security-relevant subdomains

EASM is intentionally bounded: ≤ 25 hosts per run, 5s per probe. It is not a port scanner — we don't ship one because port scanning third-party infra without authorisation is reckless. We rely on passive CT data and HTTPS HEAD requests, both of which any browser does routinely.

Cloud accounts

Connect read-only credentials for AWS, Google Cloud, or Azure at /dashboard/cloud/connect and Patchhog scans the configured account for misconfigurations on demand.

AWS

Uses an IAM role + external ID assume-role pattern. The connect screen renders a ready-to-paste trust policy — you create the role in your account with read-only permissions and paste the role ARN back into Patchhog.

Google Cloud

Paste a service-account JSON key. The recommended scope is the GCP roles/viewer role at the project level.

Azure

Provide a tenant ID + client ID + client secret + subscription ID for a registered Azure AD application with a read-only assignment.

Auto-fix for dependencies

On a scan that produced dependency findings with known fixed versions, the Fix and push button edits package.json, regenerates the lockfile, and commits straight to your default branch using your GitHub OAuth token — the commit is authored under your own GitHub identity. If branch protection blocks the push, the call surfaces the error so you can relax protection or merge manually.

The commit that lands:

  • Branch: your repository's default branch (direct push)
  • Author: your GitHub account (via OAuth)
  • Message: Security: Patchhog auto-fix (N changes)
  • Files: package.json + regenerated lockfile, plus any Dockerfile base-image bumps and the Next.js security-headers middleware if applicable

Patchhog preserves the existing range prefix (^, ~, etc.) and skips major-version bumps so the push stays safe by construction.

PR decoration

For pull-request scans, Patchhog posts inline review comments anchored to the file + line of each finding. Each comment renders:

  • Severity badge (color + emoji) and finding title
  • First six lines of the finding description
  • One-line fix recommendation
  • Footer link back to <your-app-url>/dashboard/findings/{id} + rule ID + scan ID

Comments outside the diff are silently dropped by GitHub — we don't pre-filter, since the worst case is “comment never appears,” which is the desired behaviour.

SBOM export

Every scan exposes a CycloneDX 1.5 Software Bill of Materials at GET /api/scans/[id]/sbom. The export pairs every dependency component with its CVE / GHSA vulnerabilities in the CycloneDX vulnerabilities section.

CycloneDX 1.5 is the de-facto standard accepted by SOC 2 audits and US Executive Order 14028 supply-chain compliance checks — feed the JSON straight to your auditor or to a downstream tool like cyclonedx-cli.

Notifications

Configure Slack, Discord, and Microsoft Teams webhooks at /dashboard/integrations. Each channel takes the provider's incoming-webhook URL plus a minimum-severity threshold (critical / high / medium / low / info).

On scan completion, Patchhog posts a summary card with severity counts, repo + branch / commit / PR context, and a link back to the dashboard. Channels can be temporarily disabled without deleting them, and webhook URLs are stored encrypted at rest and masked in the dashboard UI.

Local CLI

The standalone patchhog CLI runs a slimmer version of the cloud scanner directly on your laptop — useful for pre-commit and CI. It only calls the public OSV API; no auth, no telemetry, no cloud round-trip.

The CLI ships in this repository at cli/patchhog.mjs. The package is not yet published to npm, so for now you run it from a checkout:

bash
# from a clone of the patchhog repo
node cli/patchhog.mjs .                  # scan current directory
node cli/patchhog.mjs ./src --json       # machine-readable output
node cli/patchhog.mjs . --fail-on=high   # exit 1 if any finding ≥ high

# or via the npm script
npm run scan -- ./src --fail-on=high

Exit codes:

  • 0 — scan finished without violating --fail-on
  • 1 — scan finished with findings ≥ --fail-on threshold
  • 2 — fatal scanner error

The CLI focuses on the checks that matter most when running locally: hard-coded secrets, vulnerable dependencies (npm / PyPI / Go / Cargo / RubyGems via OSV), and known-malicious / typosquatted package names. SAST, IaC, DAST, EASM, and Cloud remain cloud-only.

CI / CD integration

Drop the CLI into any pipeline that runs Node 18+. The example below adds the Patchhog repo as an inline clone and fails the GitHub Actions build if any high-or-worse finding shows up:

yaml
name: security
on: [push, pull_request]
jobs:
  patchhog:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - name: fetch patchhog CLI
        run: git clone --depth 1 https://github.com/patchhog-dev/patchhog .patchhog
      - name: scan
        run: node .patchhog/cli/patchhog.mjs . --fail-on=high

For pre-commit, point a .husky/pre-commit hook at the same command — the CLI completes in single-digit seconds on small repos and prints a concise human-readable report by default. Once the package ships to npm, the git clone step collapses to a plain npx patchhog.

Webhook security

GitHub events land at POST /api/webhooks/github. Every request is verified before any work runs:

  • x-hub-signature-256 is compared against an HMAC-SHA256(body, repo.webhook_secret) using a constant-time compare
  • The repo is looked up by GitHub ID; an unknown repo returns 404 before anything else happens
  • Each repository has its own per-repo webhook secret — compromising one webhook never affects another

Reacted-to events: push, pull_request (action ∈ {opened, synchronize, reopened}), and ping (handshake). Everything else is silently acknowledged and ignored. PR scans additionally trigger inline-comment decoration once the scan finishes.

Framework mapping

Patchhog maps finding categories to specific controls across three frameworks: SOC 2 (Trust Services Criteria), ISO 27001:2022 Annex A, and the NIST Cybersecurity Framework. The mapping is intentionally conservative — we surface controls with failing evidence so a security engineer can prioritize the gap. We do not auto-attest the framework.

SOC 2 controls Patchhog covers (sample):

  • CC6.1 — logical access security (IaC, cloud, misconfig, API)
  • CC6.6 — boundary protection (IaC, cloud, DAST)
  • CC6.7 — secure protocols & credential hygiene (secrets, DAST, API)
  • CC7.1 — vulnerability detection (SAST, dependencies, malware, container)
  • CC8.1 — change management / secure SDLC (IaC)

ISO 27001 (e.g. A.5.31, A.8.2) and NIST-CSF controls follow the same evidence pattern: a finding category fails into the relevant control. The full table is visible at /dashboard/compliance and can be exported via GET /api/reports/compliance.

Data handling

What Patchhog persists per scan:

  • The finding records (file path, line, rule ID, severity, CWE, description, recommendation)
  • A short surrounding code excerpt (code_snippet) for context in the UI
  • Scan metadata: repo ID, commit SHA, branch, PR number, timing, scanner counts
  • The auto-PR URL + number, once opened

What Patchhog does NOT persist:

  • The repository's working copy — cloned into a tmp dir and discarded once the scan returns
  • Files outside the finding excerpt (no mirroring)
  • Anything cross-repo or cross-user

Cloud-account credentials and notification-channel webhooks are encrypted at rest. Webhook URLs are masked in the dashboard UI; cloud secrets are never returned over the API after creation.

FAQ

Which languages and ecosystems are supported?

Dependency scanning: npm / PyPI / Go / Cargo / RubyGems / Maven (all OSV-covered ecosystems). SAST: JavaScript, TypeScript, Python, Go, Java, Ruby. Secrets, IaC, DAST, and EASM are language-agnostic.

How long does a scan take?

For repos under 100 kLoC, end-to-end scans typically complete in well under a minute. DAST and EASM probes complete in a few seconds. The auto-PR step adds roughly one second per upgraded package.

Does Patchhog work on private repos?

Yes. Patchhog reads files via the GitHub API using your authorized OAuth scope; nothing is mirrored or cached cross-repo.

Where does the scan run?

When a background worker is configured (WORKER_URL set), scans run asynchronously and Patchhog posts back to /api/internal/scan-complete when finished. Without a worker configured, scans run in-process on the webhook request (capped at 5 minutes of Vercel runtime).

Can I self-host?

Not in v1. The CLI is fully offline, but the cloud product (dashboard, scheduled scans, auto-PR, PR decoration, notifications) runs on patchhog.dev. Reach out if self-hosting matters for your team.