arcuru/vuln-scanner
GitHub: arcuru/vuln-scanner
一个基于 LLM 的多阶段漏洞扫描器,通过对代码仓库构建持续累积的调查目录来实现深度安全审计。
Stars: 0 | Forks: 0
# vuln-scanner
LLM 驱动的漏洞扫描器,为每个扫描目标构建一个 **调查目录**
,随着目标的演进和模型的改进,跨运行积累历史记录。
```
recon → hunt → validate → dedupe → consolidate (per run)
```
## 前置条件
- Python 3.12+
- 用于依赖和环境管理的 [`uv`](https://docs.astral.sh/uv/)
- `$PATH` 中的 `git`
- 针对所选后端的 agent CLI,需通过身份验证:
- [`claude`](https://github.com/anthropics/claude-code) — 默认后端
- [`pi`](https://github.com/anthropics/oh-my-pi) — 备选后端
- 你通过自定义 `[agent.backends.*]` 条目接入的其他任何后端
## 安装
```
# 在不全局安装的情况下从 checkout 运行
uv run vuln-scanner --help
# 或者安装为 uv tool(将 `vuln-scanner` 放入 $PATH)
uv tool install .
```
## 快速开始
为调查创建一个文件夹,针对目标进行构建,运行扫描,检查状态。
```
mkdir cool-project-scan && cd cool-project-scan
# 将 target 克隆到 ./target/,写入 vuln-scanner.toml + MANIFEST.toml
uv run vuln-scanner init https://github.com/user/cool-project
# 运行扫描(使用 target 当前的 HEAD;传递 --sha 以固定 commit)
uv run vuln-scanner run -j 8
# 稍后重新运行(target 可能有新的 commit,或者有更新的 model 可用);
# 下一次 recon 会读取之前的运行记录并提议全新的调查
uv run vuln-scanner run --sha
# 查看运行历史
uv run vuln-scanner status
```
调查文件夹是自包含的。你可以移动它、归档它,或者将其提交到自己的 git 仓库中 —— 它始终保持一致。
## 扫描归档
此仓库还通过位于 [`scans/`](scans/) 的 git 子模块([`arcuru/vuln-scans`](https://github.com/arcuru/vuln-scans))对扫描记录进行归档。每个子文件夹都是一个调查目录:配置 + 清单 + 每次运行的输出。克隆的目标和临时的 worktree 被 gitignore 忽略,因此提交的内容就是审计追踪记录。
使用 `--recurse-submodules` 进行克隆,以便在工具旁边拉取扫描归档。
| 目标 | 源 |
|---|---|
| [`cmprss`](scans/cmprss/) | |
从仓库根目录,扫描现有目标或添加一个新目标:
```
# 对 target 运行扫描(位于树中的任何位置)
vuln-scanner run -C scans/cmprss -j 8
# 添加新的 target
mkdir scans/ && cd scans/
vuln-scanner init https://github.com/owner/repo
vuln-scanner run -j 8
```
## CLI 参考
```
$ vuln-scanner --help
usage: vuln-scanner [-h] {init,run,status} ...
Multi-phase LLM vulnerability scanner over a single target investigation.
positional arguments:
{init,run,status}
init Initialize an investigation directory in cwd (clones
target, writes config).
run Execute one scan run against target/ in cwd.
status List runs in this investigation.
$ vuln-scanner init --help
usage: vuln-scanner init [-h] [-c CONFIG] target_url
positional arguments:
target_url Git URL of the target repo to clone
options:
-c, --config CONFIG Path to a vuln-scanner.toml to copy in (default:
minimal built-in)
$ vuln-scanner run --help
usage: vuln-scanner run [-h] [-C DIR] [--sha SHA] [-j JOBS] [-v]
options:
-C, --dir DIR Investigation directory to operate on (default: cwd)
--sha SHA Target commit SHA to pin (default: keep current target
HEAD)
-j, --jobs JOBS Parallel workers (default: 4)
-v, --verbose
$ vuln-scanner status --help
usage: vuln-scanner status [-h] [-C DIR]
options:
-C, --dir DIR Investigation directory to operate on (default: cwd)
```
## 调查目录
`init` 用于构建,`run` 生成不可变的单次运行目录,顶层的 `SUMMARY.md` 始终指向最新的一次运行:
```
my-investigation/
vuln-scanner.toml # config (committed)
MANIFEST.toml # target URL, latest-run pointer
target/ # cloned scan target (gitignored)
worktrees/ # ephemeral worktrees (gitignored)
.vuln-scanner.lock # concurrency guard
runs/
2026-05-20T14-30-abc1234/ # ISO timestamp + short target SHA
manifest.toml # tool version, target SHA, status, summary
config.toml # effective config snapshot for this run
logs/.log # agent stdout (or SDK event stream)
transcripts/.jsonl # full Claude transcript per task
recon/
HUNT_QUEUE.json
task.toml # backend, model, session_id, timings
hunt//
FINDING.md
task.toml
validate//
VERIFICATION.md
task.toml
dedupe/FINDINGS.md
consolidate/
SUMMARY.md # cumulative across all runs
task.toml
SUMMARY.md → runs//consolidate/SUMMARY.md
```
每个运行目录都是自描述的:`config.toml` 是运行时对 `vuln-scanner.toml` 解析后的视图,而每个任务的 `task.toml` 记录了确切的后端调用(argv 或 SDK 选项)、session UUID、使用的模型、持续时间和成本。匹配的 `transcripts/.jsonl` 是从 `~/.claude/projects/` 中复制出来的完整 Claude session 日志。
`init` 写入的 `.gitignore` 涵盖了 `target/`、`worktrees/` 和 lockfile —— 因此你可以在调查文件夹中运行 `git init` 并跟踪配置 + 运行情况,而无需将目标的完整历史记录一并拖入。
## 工作原理
每个阶段都在脱离 `target/` 的独立 git worktree 中运行,从而按任务隔离 agent 产生的制品:
1. **recon** — 单个任务。映射架构并生成 `HUNT_QUEUE.json`。在后续的延续运行中,还会读取先前运行的 `SUMMARY.md` 以及自上次目标 SHA 以来的 git diff,随后生成一个包含全新调查和值得重新审查的队列。
2. **hunt** — 从队列中进行发散。每个条目代表特定范围内的一个攻击类别。每个任务生成一个 `FINDING.md`。
3. **validate** — 从 hunt 任务中进行发散。对每个发现进行对抗性审查。每个任务生成一个 `VERIFICATION.md`。
4. **dedupe** — 单个任务。按根本原因对确认的发现进行分组,记录被拒绝的调查以便未来的 recon 可以跳过它们,并记录*失败*的调查(即 agent 在产生输出前崩溃或超时的任务 —— 结果未知,代码路径未被排除)以便未来的运行重新尝试它们。生成 `FINDINGS.md`。
5. **consolidate** — 单个任务。生成累积的 `SUMMARY.md`,其中每个发现都相对于先前的运行被标记为 **NEW** / **PERSISTS** / **FIXED** / **REGRESSED**,并且包含一个“失败调查”部分,列出了本次运行中结果未知的任务。
每次运行都会从 `.done` 标记处恢复 —— 如果中断,重新运行 `run`(不带 `--sha`)会在相同的运行目录中从上次中断的地方继续。
同一调查文件夹中并发的 `run` 调用会通过 lockfile 拒绝执行。
如果 recon 判定没有新的内容可供调查(在未更改目标上的延续运行),它会写入一个空队列,流水线将提前退出。
## 配置
分为两层:一个 **prompt profile**(包含 prompt 函数的 Python 模块,以及 markdown 内容)和一个 **TOML config**(设置覆盖)。
### Prompt profile(Python + markdown)
内置的 profile 是 `vuln-scan`(位于 `src/vuln_scanner/configs/vuln_scan.py`)。Prompt 内容与其同存于 `src/vuln_scanner/configs/prompts/` —— 每个阶段一个 `.md` 文件,在渲染时替换 `$variable` 占位符:
```
configs/
vuln_scan.py # settings + glue (loads + renders the .md files)
prompts/
_environment.md # shared snippet injected into every prompt
recon.md # uses $prior_runs_path for continuation runs
hunt.md # uses $attack_class, $scope, $entry_point, …
validate.md
dedupe.md
consolidate.md # uses $prior_runs_path
```
要微调发送给 agent 的内容,只需编辑 markdown —— 无需更改 Python。profile 模块上所需的 prompt 函数:
- `recon_prompt(*, prior_runs_path: str = "") -> str`
- `hunt_prompt(*, attack_class, scope, function, entry_point, rationale, arch_summary) -> str`
- `validate_prompt() -> str`
可选:`dedupe_prompt()`、`consolidate_prompt(output_dir, *, prior_runs_path="")`。
通过复制 `vuln_scan.py`(以及 `prompts/` 目录)来编写你自己的 profile,并在 `vuln-scanner.toml` 中通过 `[scan] prompt_profile = "..."` 指向它。
### 设置 (TOML)
`init` 会将一个最小化的 `vuln-scanner.toml` 写入调查文件夹(除非你传入 `-c ` 来复制你自己的配置):
```
[scan]
prompt_profile = "vuln-scan"
[agent]
backend = "claude"
# [agent.models]
# recon = "claude-sonnet-4-6"
# hunt = "claude-sonnet-4-6"
# validate = "claude-opus-4-7"
```
请参阅 [`vuln-scanner.example.toml`](vuln-scanner.example.toml) 获取带有注释的完整选项集合。关键部分:
| 部分 | 用途 |
|---|---|
| `attack_classes` (顶层) | 要扫描的漏洞类别 |
| `[scan]` | Profile、分支前缀、并行度、超时 |
| `[scan.task_timeouts]` | 每个阶段的超时覆盖(秒) |
| `[agent]` | 后端名称和标志 |
| `[agent.models]` | 每个阶段的模型名称 |
| `[agent.backends.]` | 在配置中定义自定义后端 |
| `[output]` | 每个阶段的输出文件名 |
| `[files]` | 文件扩展名和排除目录 |
### 后端
内置后端:
- `claude` — 以子进程方式运行 Claude Code CLI (`claude -p`);默认后端。
- `claude-sdk` — 使用进程内的 [`claude-agent-sdk`](https://pypi.org/project/claude-agent-sdk/)
Python 库。使用与 `claude` 相同的模型和工具,但会将结构化事件(assistant 轮次、工具调用、带有 token 和成本信息的最终 `ResultMessage`)流式传输到每个任务的日志文件中。
- `pi` — Oh My Pi agent CLI。
通过 `[agent] backend = "..."` 进行设置。
可以直接在 TOML 中定义自定义后端 —— 无需 Python 代码:
```
[agent]
backend = "gemini"
[agent.backends.gemini]
executable = "gemini-cli"
model_flag = "--model"
prompt_flag = "--prompt"
extra_args = ["--yes"]
```
字段:`executable`(必需)、`prompt_flag`(必需)、`model_flag`(可选)、`extra_args`(可选)。生成的命令如下:
```
gemini-cli --yes --model --prompt
```
对于需要超越标志的自定义逻辑的后端,请在 `src/vuln_scanner/claude.py` 中实现 `Backend` 协议,并将其添加到 `BACKENDS` 注册表中。
### 超时
`task_timeout` 设置全局默认值(0 = 无超时)。`task_timeouts` 会覆盖每个阶段的设置:
```
[scan]
task_timeout = 0 # global default: no timeout
[scan.task_timeouts]
hunt = 900 # 15 minutes per hunt task
validate = 600
```
当触发超时时,agent 子进程会先收到 SIGTERM,然后在 5 秒后收到 SIGKILL。
## 开发
```
# 安装 dev dependencies
uv sync --extra dev
# 运行 tests
uv run pytest tests/ -v
# Type check
uv run pyright src/
```
## 致谢
多阶段的 recon → hunt → validate → dedupe → consolidate 架构改编自 Cloudflare 在
["Cyber frontier models: Claude's strengths in software security"](https://blog.cloudflare.com/cyber-frontier-models/)
中描述的设计,该文章阐述了本项目在 Claude Code(或任何其他 agent CLI)之上重新实现的 agentic 漏洞研究流水线。Cloudflare 进程内的 gapfill / hunt2 / validate2 第二轮检查,在这里的实现方式是*再次运行该工具* —— 下一次运行的 recon 会读取先前运行的发现,并在生成队列时参考它们。
## 许可证
AGPL-3.0-or-later。请参阅 [`LICENSE.txt`](LICENSE.txt)。
标签:DLL 劫持, Python, Python安全, 大语言模型, 无后门, 网络安全研究, 逆向工具