MCPcopy Create free account
hub / github.com/alpha-omega-security/scrutineer

github.com/alpha-omega-security/scrutineer @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
2,368 symbols 9,711 edges 196 files 799 documented · 34% updated 1d agov2026.08.11.1 · 2026-08-11★ 18730 open issues

Browse by type

Functions 2,165 Types & classes 203
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

scrutineer

A local tool for scanning open source repositories for security vulnerabilities and managing the disclosure process. You add a repo by URL, scrutineer runs a pipeline of agent skills against it inside a container, and presents the results in a web UI where you can triage findings, identify maintainers, and track disclosures. The agent CLI is pluggable: claude-code by default, or codex, opencode, or GitHub Copilot CLI with -backend.

Quick start

You need one supported container runtime: Docker (the default), rootless Podman, or Apple's container CLI.

Install Scrutineer from Homebrew on macOS or Linux:

brew install scrutineer

Alternatively, download the Linux or macOS archive for your architecture from GitHub Releases, verify it against SHA256SUMS, and put scrutineer on your PATH. The macOS archives are currently unsigned and not notarized, so macOS may present a Gatekeeper warning even after you verify the checksum and GitHub build-provenance attestation.

To build or run from source instead, install Go 1.26+:

git clone https://github.com/alpha-omega-security/scrutineer
cd scrutineer

Authenticate the default claude-code backend with either a Claude Code subscription token (Max, Pro, Team, or Enterprise) generated by the Claude CLI:

claude setup-token
export CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-...

or an Anthropic API key from console.anthropic.com:

export ANTHROPIC_API_KEY=sk-ant-api03-...

Start a downloaded or installed binary with Docker:

scrutineer

Select another installed runtime explicitly:

scrutineer --runtime podman
scrutineer --runtime apple

The existing source-checkout command remains supported:

go run ./cmd/scrutineer -skills ./skills

Then open http://127.0.0.1:8080. The explicit -skills ./skills directory makes the checkout command useful while developing skills because it overrides the copies embedded in the binary. It is optional for ordinary use because Scrutineer ships its built-in skills and per-ecosystem runner profiles inside the executable.

You can also build a checkout-independent executable and run it from another directory:

go build -o scrutineer ./cmd/scrutineer
mkdir -p ~/.local/bin
install -m 0755 scrutineer ~/.local/bin/scrutineer
scrutineer

Precompiled binaries cover Linux and macOS on amd64 and arm64. Run scrutineer --version (or scrutineer version) to see the application version, source commit, build timestamp, and exact runner-image digest paired with that release.

The executable does not bundle Docker, Podman, or Apple's container CLI. Scrutineer remains a host application that asks the selected external runtime to launch an ephemeral runner container for each scan; it materialises the embedded profile Dockerfiles under the data directory when docker/profiles is not available from a source checkout. Content-addressed skill and profile bundles from older versions are retained because existing skill records may still reference their auxiliary files; incomplete extraction directories older than 24 hours are removed automatically. To run under codex, opencode, or copilot instead, see the Codex backend, Opencode backend, and Copilot backend sections; only the credential and -backend flag change.

Large batches pause automatically at an account-level rate limit or quota wall. When claude-code is running on a subscription token it emits a rate_limit_event carrying the reset time, and scrutineer re-queues the paused batch after that reset; API-key accounts and the codex/opencode/copilot backends report the error without a reset time, so those batches stay paused for manual resume from the /usage page, which also shows the most recent per-window status.

Scrutineer uses Docker by default: each scan runs in an ephemeral container with a read-only source mount and an egress allowlist proxy. The paired runner image (ghcr.io/alpha-omega-security/scrutineer-runner) is pulled on first use, so the first scan is slower while it downloads. A host without the selected runtime fails startup rather than silently weakening isolation; --no-container is the explicit, Claude-only escape hatch for running directly on a trusted host.

Click Add repository in the sidebar, paste a git HTTPS URL, and scrutineer enqueues the triage skill. To scan a maintained branch instead of the default, fill the Branch field (it suggests the remote's branches as you type and also accepts a tag or commit), or append a /tree/<branch> suffix to the URL; the suffix also works one-per-line when bulk-importing. Triage then enqueues the rest of the pipeline in parallel. Metadata and package lookups finish in seconds; the security deep-dive takes a few minutes depending on repo size. Open the repo page and switch to the Scans tab to watch progress, or wait for the Findings tab to fill in.

To scan one package inside a monorepo, append #<sub/dir> to the URL -- e.g. https://github.com/rails/rails#activesupport (or paste a .../tree/<branch>/<sub/dir> URL). Scrutineer scopes the whole pipeline to that sub-folder and gives the sub-package its own page, findings, packages, advisories, disclosure channel, and export, instead of rolling every package up under the repository. By default a sub-package scan is confined to its own sub-folder (siblings pruned, .git kept), widening to the whole repository automatically if the sub-package cannot resolve its dependencies in isolation; set subproject_scope: soft to always scan against the whole tree, or monorepo_attribution: false to keep registry data repo-wide (see scrutineer.sample.yaml). The subprojects skill also auto-discovers a monorepo's sub-packages, so you can scan them from the repo page without composing URLs by hand. Findings, packages, advisories, the disclosure channel, and export are attributed per sub-package; dependents, maintainers, posture, and health stay repo-wide. There is no per-sub-package schedule -- to re-scan sub-packages on a cadence, drive the local API from cron or a systemd timer (see scripts/rescan-subprojects.sh).

To onboard a whole GitHub org at once, open Add multipleImport a whole org and enter the org (or user) login. Scrutineer fetches every repository and queues each one with the default scan set, skipping forks, archived repos (unless you opt in), and any URL already in the database. Set GITHUB_TOKEN to raise GitHub's unauthenticated rate limit when importing large orgs.

You can also scan a directory on disk, useful before pushing, or for code not hosted on a git forge. Paste an absolute path (/path/to/project) in the same Add repository field. Scrutineer copies the directory into a per-scan workspace and runs the default skill set; skills that need a forge URL or ecosyste.ms enrichment (advisories, exposure, fork, maintainers, metadata, packages, public-issue, report-upstream) are skipped automatically. Symlinks are recreated as-is rather than dereferenced during the copy; in container mode their targets then resolve inside the container, so host files reached only through such a link are not visible to skills. Under --no-container the kernel dereferences them normally, so only point scrutineer at trees you trust.

The optional analysis tools (semgrep, zizmor, git-pkgs, brief) are bundled in the runner image, so you don't need them installed locally when the container runner is in use.

Git authentication

Scrutineer shells out to git clone with no explicit token passing, so it uses whatever credentials are already configured on the host: SSH keys, credential helpers, gh auth login, a .netrc file, or the macOS keychain.

To scan private repos, check that git clone https://github.com/org/repo works in the same environment you launch scrutineer from before adding the URL.

Common setups:

# GitHub CLI (easiest)
gh auth login

# Git credential helper
git config --global credential.helper store   # or osxkeychain / manager-core

# SSH-based clone URLs are not supported -- scrutineer only accepts https:// URLs.
# Use a credential helper to authenticate HTTPS clones instead.

When running inside Docker (docker run ...), the container has no access to host credentials. Mount a credential store or set GIT_ASKPASS to provide access to private repos from inside the container.

When the containerised runner is active (the default when a container runtime is available), each scan runs in a separate container but the clone happens on the host before the source is mounted in. Host credentials are used for the clone and never enter the container.

Features

Scanning and analysis

  • Skill-based scan pipeline -- every scan is a skill on disk (SKILL.md + schema + optional scripts) staged where the active backend expects it. The default pipeline for a new repo is itself a skill (triage) that enqueues the others; edit its SKILL.md to change what runs
  • Structured findings -- vulnerability reports parsed into a database with severity, CWE, location (linked to source), affected versions, and a six-step analysis trace
  • Threat model view -- the project's security contract (components, entry-point trust table, properties provided and disclaimed, known non-findings) rendered from the threat-model scan, falling back to the deep-dive's boundaries and sink inventory on older repositories
  • Dependency exploration -- dependency and dependent tables with one-click import to scan any package's source repository
  • Package registry data -- downloads, dependents, versions, and registry links for every published package
  • Known advisories -- existing CVEs and security advisories pulled automatically
  • Maintainer identification -- model-backed skill combining commit history, issue/PR activity, and registry ownership to identify who to contact for disclosure
  • CWE catalogue -- embedded MITRE CWE data with tooltips on finding tables and full descriptions on finding pages
  • Reachability analysis -- trace sinks found in dependencies through application code to see which are actually reachable
  • Rescan dedup -- findings carry a content fingerprint so re-running a scan updates existing rows instead of creating duplicates; same-fingerprint hits within one scan collapse to a single finding with a +N expandable location list, and findings that stop appearing are marked "not seen" with a miss count

Triage and disclosure workflow

  • Finding workflow -- guided triage flow from new through verification, disclosure, and publication with human gates at each step
  • Cheap-classifier pre-sort -- the revalidate skill auto-enqueues for High/Critical deep-dive findings and every imported finding, emitting true_positive / false_positive / already_fixed / uncertain plus an optional severity adjustment; a true_positive on a High/Critical finding chains into verify automatically
  • Audit queue -- random sample of recent low and false-positive verdicts at /audit so the operator can spot-check the classifier; each review records an agreement-or-overturn verdict on the finding
  • Exploited-in-the-wild flag -- analyst-only yes/no field on findings with free-text evidence, surfaced on the finding page, in the OSV database_specific block, in CSAF audit notes, and in markdown report exports
  • Breaking-change classifier -- the breaking-change skill runs over a suggested-fix diff plus the top dependents, recording breaking / non_breaking / unknown with a rationale and the list of affected dependents
  • Mitigation guidance -- the mitigate skill drafts short-term workarounds and an optional semgrep rule per finding, separate from the code fix
  • CVSS v3.1 and v4.0 -- both vectors stored side by side with derived scores; analyst form, OSV/CSAF exports, and the disclose skill all carry both forward, with the v4 metric set kept distinct from v3
  • Release watch -- the release-watch skill closes the gap between fix-landed and fix-shipped: once a finding reaches fixed, the skill polls upstream releases and records the release tag, URL, and timestamp when it appears
  • CNA matching -- identify the CVE Numbering Authority whose scope covers a repo so disclosures go to the right contact
  • Upstream reporting -- file a finding on the upstream repository through GitHub's private vulnerability reporting with the proposed patch attached, and push the fix to the temporary private fork when GitHub grants access. A PVR report is hard to unsend; before pointing this at an external repository, run it once end-to-end against a repository you control with PVR enabled to confirm the body shape and patch attachment land the way you expect. When upstream has no PVR available, follow the runbook in docs/disclosure-fallback.md

Imports and exports

  • SBOM import -- upload a CycloneDX or SPDX document, resolve each component to a source repository, and queue scans automatically
  • Finding import -- POST SARIF, CSV, markdown, or minimal-JSON findings from external scanners and pentest reports into the same workflow as native scans, with fingerprint dedup against re-imports
  • Free-form ingest -- when the format sniffer in /api/v1/import cannot place a payload, the ingest skill normalises it against the source checkout (resolving locations) before it enters the finding

Extension points exported contracts — how you extend this code

browse all types & interfaces →

Core symbols most depended-on inside this repo

browse all functions →

Shape

Function 1,746
Method 419
Struct 190
TypeAlias 9
FuncType 2
Interface 2

Languages

Go99%
TypeScript1%
Python1%

Modules by API surface

internal/web/server_test.go153 symbols
internal/web/server.go98 symbols
internal/worker/skill_parsers_test.go54 symbols
internal/db/db.go50 symbols
internal/worker/container.go49 symbols
internal/worker/worker.go43 symbols
internal/web/finding_csaf.go41 symbols
internal/worker/skill.go40 symbols
internal/web/repo_report.go40 symbols
internal/skills/parse_test.go40 symbols
internal/web/api_export_test.go36 symbols
internal/worker/container_test.go34 symbols

For agents

$ claude mcp add scrutineer \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page