zeroshi
turns claude code / opencode into a vulnerability scanner
An AI vulnerability scanner. Point it at a git repo and it clones the code, runs a coding agent with a structured vulnerability-hunting methodology, and collects the findings the agent proves — surfaced on a local web board or emitted as JSON. A findings-triage/verification pass re-checks each candidate so what lands is signal, not noise.
How it works
- Harness-agnostic. The agent is a swappable backend behind
ScanRunner(scanner/base.py).ClaudeCodeRunnershells out to theclaudeCLI;OpenCodeRunneris the same interface foropencode. Downstream code never knows which one ran. - Structured contract, no markdown parsing. The agent appends findings to
findings.jsonl— one JSON object per line — as it works; each line is validated againstscanner/schema.pyand malformed lines are dropped. Appending per-finding means an interruption never loses recorded work. - Sandbox is the isolation boundary. Running an autonomous agent on
untrusted source is RCE pointed at yourself. For untrusted repos, run the scan
in the disposable container (
sandbox/Dockerfile), one per scan.
Prerequisites
- Python 3.11+
- git — used to clone scan targets
- ripgrep (
rg) — the agent's search tool (apt install ripgrep/brew install ripgrep) - A coding-agent backend (pick one):
- Claude Code CLI (default) — requires Node.js 18+, then
npm install -g @anthropic-ai/claude-code. Auth comes from your logged-in CLI: runclaudeonce and sign in. - opencode — set
OPENROUTER_API_KEYin.env(see below) and select it with--runner opencode.
- Claude Code CLI (default) — requires Node.js 18+, then
- Docker — only needed for sandboxed scans.
Setup
git clone [email protected]:code-zm/zeroshi.git
cd zeroshi
python -m venv .venv
./.venv/bin/pip install -r requirements.txt
cp .env.example .env # then edit — see below
.env is optional for the default Claude Code runner (it authenticates through
your logged-in claude CLI). Fill it in when you want:
OPENROUTER_API_KEY— required only for theopencoderunner.SMTP_*/NOTIFY_TO— optional; a finished scan emails you a summary. Leave the SMTP fields blank to disable (the worker just skips sending).ZEROSHI_WORKERS,ZEROSHI_LIMIT_BUFFER— worker-pool tuning.
See .env.example for the full annotated list.
Run the web app
python app.py
Open http://127.0.0.1:8077, paste a repo URL, hit Scan. Press Ctrl-C
to stop. (python app.py auto-uses .venv if your system Python is missing the
deps; host/port override with ZEROSHI_HOST / ZEROSHI_PORT.)
Run a single scan from the CLI (no web)
./.venv/bin/python -m scanner.scan https://github.com/owner/repo --keep
--keep preserves the clone (and its findings.jsonl / FINDINGS.md) for
inspection. Use --runner opencode --model <slug> to swap the backend, or
--token <git-token> for a private repo.
Run sandboxed (untrusted repo)
docker build -f sandbox/Dockerfile -t zeroshi-scan .
docker run --rm \
-e ANTHROPIC_API_KEY \
--memory 4g --cpus 2 --pids-limit 512 \
zeroshi-scan https://github.com/owner/repo
Run a backlog (worker pool)
The web app drains a queue of jobs ZEROSHI_WORKERS at a time. Feed it from a
list of repo URLs (one per line, # comments ok):
./.venv/bin/python -m web.seed my_targets.txt --top-up 4
When a scan hits a plan usage limit, the pool pauses and resumes automatically when the window resets, so a backlog can run unattended.
License
GPL-3.0 — see LICENSE.