back to projects

zeroshi

turns claude code / opencode into a vulnerability scanner

Python
<p align="center"> <img src="web/static/zeroshi-logo.png" alt="Zeroshi" width="260"> </p> <h1 align="center">Zeroshi</h1>

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). ClaudeCodeRunner shells out to the claude CLI; OpenCodeRunner is the same interface for opencode. 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 against scanner/schema.py and 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: run claude once and sign in.
    • opencode — set OPENROUTER_API_KEY in .env (see below) and select it with --runner opencode.
  • 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 the opencode runner.
  • 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.