Local-first daemon for recurring AI-assisted vulnerability research across your own code folders.
Point it at local repositories, let your configured agents repeatedly audit them, and keep unreviewed critical findings visible until someone triages them.
The app icon is served as the favicon, the install manifest icon, the header brand mark, and the top-right review queue button: vulnerability-daemon-icon.svg.
- Runs recurring security audits over local folders.
- Rotates across configured targets.
- Uses local agent CLIs:
codex,claude, orcursor-agent. - Randomizes agents when
agentis set torandom. - Probes agent readiness and excludes non-ready agents from random selection.
- Stores markdown reports, normalized findings, raw logs, run metadata, and SARIF.
- Tracks critical review state:
new,reviewed,accepted,false_positive,fixed. - Serves a local dashboard and JSON API on
127.0.0.1. - Exports SARIF and GitHub issue draft markdown.
- Optionally sends webhook notifications for new high-severity findings.
The core promise: never let a new critical finding disappear into a terminal log.
The normal user flow is app-like:
- Start
vuln-daemon. - It lives in the menu bar on macOS.
- Reviews run on the schedule in your config.
- Critical findings stay visible in the dashboard until reviewed.
The CLI commands remain available for automation, CI experiments, and debugging.
From source:
cargo install --path .During development, use cargo run -- in place of vuln-daemon.
Release automation builds platform tarballs, and macOS release jobs also produce
a .app bundle. A Homebrew formula template lives at
packaging/homebrew/vulnerability-daemon.rb.template.
Signed release binaries are still planned.
Start the app:
vuln-daemonor:
vuln-daemon startOn first run it asks for one local repo/folder to watch, writes the app config, starts the local daemon, and opens the dashboard. On macOS it also stays in the menu bar with actions for opening the dashboard, starting a review now, opening the config, and quitting.
Default app config locations:
- macOS:
~/Library/Application Support/Vulnerability Daemon/config.json - Linux:
~/.config/vulnerability-daemon/config.json - Windows:
%APPDATA%\Vulnerability Daemon\config.json
Use a specific config when you want to keep project-local state:
vuln-daemon start --config ./vuln-daemon.config.jsonCreate a config without starting the app:
vuln-daemon initWrite the example config directly:
vuln-daemon init-config ./vuln-daemon.config.jsonRun one review immediately:
vuln-daemon run-once --config ./vuln-daemon.config.jsonRun the daemon without menu-bar integration:
vuln-daemon start --config ./vuln-daemon.config.json --no-trayOr run the raw HTTP server:
vuln-daemon serve --config ./vuln-daemon.config.jsonExport SARIF after runs:
vuln-daemon export-sarif --config ./vuln-daemon.config.json --output ./results.sarifExport GitHub issue drafts:
vuln-daemon export-issues --config ./vuln-daemon.config.json --output-dir ./issue-draftsReparse existing reports after upgrading parser logic:
vuln-daemon reindex --config ./vuln-daemon.config.jsonCheck local agent readiness and config posture:
vuln-daemon doctor --config ./vuln-daemon.config.jsonSee config.example.json.
Important fields:
bind_host: must be127.0.0.1for the MVP.output_dir: where runs and review state are stored.schedule.interval_seconds: seconds between scheduled runs.schedule.run_on_start: whetherserveruns immediately on startup.agent_timeout_seconds: max seconds before a stuck agent run is killed.agent:random,codex,claude,cursor, ornone.notifications.webhook_url: optional Slack/Discord/custom webhook URL for new findings.targets: local folders to audit.targets[].prompt_pack: one ofgeneric,webapp,backend,smart-contract, orchain.
agent: "random" chooses one installed agent from codex, claude, and
cursor-agent after a non-interactive readiness probe succeeds.
Set model only when you want to force a provider-specific model flag. Leave it
as null to let each local agent use its own default model.
For a compiled binary:
cargo build --release
./target/release/vuln-daemon start --config ./vuln-daemon.config.jsonThe daemon binds only to 127.0.0.1.
GET /api/statusGET /api/runsGET /api/runs/<run_id>/reportGET /api/findingsGET /api/sarifGET /api/agent-healthGET /api/configPOST /api/runPOST /api/cancelPOST /api/open-configPOST /api/findings/<finding_id>/review
Review request body:
{
"status": "reviewed",
"note": "Confirmed and filed internally."
}Allowed statuses:
newreviewedacceptedfalse_positivefixed
out/vulnerability-daemon/
state.json
reviews.json
runs/
20260427T090000Z-my-repo/
prompt.md
report.md
findings.json
results.sarif
meta.json
agent.stdout.log
agent.stderr.log
{
"bind_host": "127.0.0.1",
"port": 8831,
"output_dir": "./out/nibiru-dogfood",
"agent": "random",
"model": null,
"agent_timeout_seconds": 7200,
"schedule": {
"interval_seconds": 3600,
"run_on_start": false
},
"targets": [
{
"name": "nibiru",
"path": "~/code/sai-project/nibiru",
"scope": "Cosmos SDK chain security: consensus safety, module authority, x/evm and precompile boundaries",
"prompt_pack": "chain",
"prompt": "Prioritize confirmed code-backed findings with concrete attack paths."
}
]
}Examples are included for:
Both examples run the HTTP/scheduler daemon without menu-bar UI. They assume you
have installed the compiled binary somewhere stable and created a config file.
The dashboard should remain bound to 127.0.0.1.
This MVP intentionally binds to 127.0.0.1 only. Do not expose it directly on a
public network. Reports can contain sensitive vulnerability details, source paths,
and exploit sketches.
Read the full security model before using this on private or sensitive repositories.
- write-token for review and run-trigger endpoints
- redacted public mode
- per-project report retention policies
- signed run metadata
- local-first GitHub/GitLab handoff that makes network export explicit
- prompt-pack marketplace


