openaudit architecture
What a run touches, from entry point to report, and which aspects each target kind is audited for. Generated from the auditor registry on 2026-10-13.
Pipeline
Every entry point drives the same engine. Each auditor runs in isolation: a missing tool becomes skipped, a crash or timeout becomes error, and the rest of the run carries on.
Entry points
apps/cli · packages/mcp · apps/server + packages/api · apps/web- CLI
openaudit: audit, list, doctor, init, mcp, schema - MCP server (stdio) for Claude Code, Cursor, Codex
- HTTP API (Hono + oRPC) with SSRF guard
- Web app (TanStack Start)
- GitHub Action (
action.yml): PR diff mode, SARIF, report artifact
Target detection
core/target.ts- Directory, file,
http(s)://URL,image:<ref>orcloud:<provider> - Resolves to one or more of 7 kinds: codebase, url, webapp, container, iac, mobile, cloud
- Config:
--configis trusted; a target's own config is read with restrictions
Engine
core/engine.ts- Selection:
--only,--exclude,--category; untrusted config can only narrow - Concurrency (default 4), per-auditor timeouts
- Correlation: one issue reported by several tools is kept once and lists who confirmed it
- Fingerprints, baseline, suppressions and
--diff <ref>(changed files only)
Scoring
core/scoring.ts- 0–100 score and A–F grade overall and per category
- Severity: critical, high, medium, low, info
--fail-ongate → exit 0 ok, 1 findings, 2 usage error- Optional
--aiinsights: prioritised summary
Reports
core/reporters- Terminal
- JSON (versioned schema,
openaudit schema) - SARIF for code scanning
- Markdown
- Interactive HTML: overview, a tab per area, OWASP/CWE view
Auditors by target
Hover a chip for its title and the tool it wraps. Click a chip or a matrix cell to highlight related auditors. An auditor that serves several target kinds appears in each column.
--only)
Coverage: category × target kind
Each cell counts auditors that report that category for that kind; the small line splits them into built-in / external / agentic. Red cells have no auditor; grey dashes mark combinations that don't apply.
Running with AI agents
The playbooks cover work that static rules can't do: following data flows, walking authenticated journeys, judging architecture. They run two ways.
In-process: --agentic
openaudit drives the Claude Agent SDK itself. Needs ANTHROPIC_API_KEY or Claude Code auth. Agents can read and search the code but not write, edit, run shell commands or browse the web. Browser playbooks go through a guard.
- Engine selects the agentic auditors for the target kind
- Each of the 10 playbooks runs as its own agent session
- The agent records each confirmed issue with
report_finding; HTTP requests are limited to the target origin agent.deepsec(Vercel deepsec) is opt-in only, with $5 / 30 min / 25-file caps by default
Agent-in-the-loop: MCP
Your own agent (Claude Code, Cursor, Codex) calls openaudit as a tool, runs the deterministic audit, then investigates with a playbook and submits what it found.
detect_target→run_auditlist_playbooks→get_playbook- Agent investigates with its own tools
submit_findingsmerges results into the report;compare_reportsdiffs runs
Trust boundary
The target is treated as hostile input. These rules come from issues reproduced during development.
- A target's
openaudit.config.jsoncan only narrow the default set. It cannot enable opt-in or agentic auditors, send data, spend money, add headers or switch off the--fail-ongate. - JS audits (npm, pnpm, bun) run on a scratch copy of the lockfile and
package.json, so the project's.npmrcproxy settings and.pnpmfile.cjshooks are never loaded. - Git calls force
core.fsmonitor=falseandcore.hooksPath=/dev/null;--diffand deepsec compare commits rather than the working tree, so clean filters never fire; history scans run on a fresh mirror clone. - Linters whose config runs code (ESLint, clippy, mypy, golangci-lint) are opt-in; tsc is openaudit's own copy, oxlint gets a config with JS plugins stripped, and Spectral never reads the project ruleset.
- ZAP active scanning is refused unless the host is on an allow-list in a trusted
--config. - Brakeman gets an empty config, so the app's
config/brakeman.ymlcan't load extra checks. pa11y and deepsec run from temp dirs. - Slow, costly, traffic-heavy or code-executing tools are opt-in: .
Still open
Red = worth doing next. Grey = larger scope or blocked upstream.
Run the AI paths for real
--agentic and --ai have never run against the live API. Doing so costs money, so it waits for a go-ahead.
Reconstructed fixtures
ZAP active scan, Prowler, golangci-lint v2, cargo-audit and the deepsec export are still parsed from documented formats rather than real recordings.
Merge IaC and container findings
Checkov, KICS, Kubescape, kube-linter and the built-in checks report the same misconfiguration under different rule ids with no shared tag, so they are not merged yet. Needs a rule-equivalence map.
CVSS v4 scores
v4 vectors fall back to the advisory database's own label, which is usually present. Scoring them directly needs the MacroVector tables.
DNSSEC
Node's resolver can't validate signatures, so DNSSEC is skipped rather than guessed.
iOS accessibility
Compiled storyboards and nibs aren't analysed; iOS gets Info.plist hints only.
ASVS, SOC 2 and CIS views
The report maps findings to OWASP Top 10 and the CWE Top 25. Mapping to ASVS, SOC 2 or CIS controls needs curated data.