一个包含故意存在漏洞的应用的 DAST 基准测试套件,附带用于为扫描器评分的真实答案键。
⚠️ 本仓库包含故意不安全的应用程序。 它们的存在 仅用于对安全工具进行基准测试——DAST 扫描器、SAST 引擎和 LLM 安全代理。每个应用都绑定到
127.0.0.1,带有醒目的横幅,并且 不保存任何真实数据。切勿将其中任何内容部署到公共网络上。
一套 19 个故意存在漏洞的应用,每个技术栈一个,每个都带有 有文档记录、可机器检查的真实答案。其目的在于衡量 扫描器或代理 (a) 发现植入漏洞的能力,(b) 忽略紧邻其旁的 安全近似代码的能力,以及 (c) 在已修补的孪生应用上 不产生幻觉发现的能力。
19 个应用 · 549 个植入漏洞 · 146 个近似漏洞 · 546 个可运行 PoC ·
594 个已编目端点。 每个应用都在 127.0.0.1:13311 上启动,附带
vuln/+safe/ 孪生对以及单镜像 --solo 构建。dynast-bench list
实时打印此表;dynast-bench surface <app> 打印其端点目录。
| 应用 | 技术栈 | 数据存储 | 漏洞 | 近似漏洞 | 文档 |
|---|---|---|---|---|---|
| aspnet | C# / ASP.NET Core Razor Pages | SQL Server | 28 | 12 | 计划 |
| fastapi | Python / FastAPI + Jinja2 | Postgres | 26 | 5 | 计划 |
| gin | Go / Gin | Postgres | 12 | 7 | 自述文件 |
| golang | Go / chi | Postgres | 26 | 4 | 计划 |
| graphql | Node / GraphQL 16 仅 API | Postgres | 31 | 6 | 计划 |
| jsp | Java / JSP + Servlets (Tomcat) | Postgres | 28 | 6 | 计划 |
| laravel | PHP 8.3 / Laravel 11 + Blade | MySQL | 25 | 7 | 计划 |
每个技术栈的额外辅助组件(Mailpit、MinIO、Redis、Jenkins、Prometheus、Ollama 等) 列于下方 应用 部分。
每个技术栈的设计文档位于 benchmark-plans/ 中——
请从那里开始查看每个应用的完整漏洞目录。本 README 是
操作指南:仓库的布局方式以及如何运行和评分一个应用。
每个植入的漏洞都带有 CWE 和 OWASP 类别。按类别汇总——每个 漏洞只计数一次,归入其主 CWE 下——植入的漏洞大致 分布如下(汇总最后在 480 个漏洞时重新生成;上表中的每个应用计数为当前值):
| 类别 | CWE | 漏洞数 | 应用数 |
|---|---|---|---|
| 敏感数据暴露(错误、日志、调试端点、备份、源代码) | 200, 209, 489, 524, 532, 538, 540, 548 | 39 | 16 |
| 默认 / 硬编码 / 泄露的凭据 | 321, 522, 798, 1104, 1392 | 38 | 18 |
| 缺失或损坏的授权(BFLA、垂直 + 水平) | 269, 284, 285, 668, 862, 863 | 37 | 18 |
| 跨站脚本(反射型 · 存储型 · DOM) | 79 | 28 | 16 |
| 认证绕过 · 弱会话 · JWT 验证 | 287, 288, 290, 306, 347, 384, 613, 614, 1385 | 28 | 13 |
| SQL 注入(包括二阶、ORDER BY、NoSQL) | 89, 943 | 27 | 17 |
| 代理 / 解析器解释冲突(路径混淆、头部信任) | 345, 348, 349, 436, 441, 693, 697, 706, 807 | 27 | 10 |
| SSRF(包括盲注、重定向链、仅内部接收器) | 918 | 20 | 17 |
| IDOR / BOLA(用户控制的对象键) | 639 | 19 | 17 |
| 路径遍历 · LFI/RFI · zip slip | 22, 98 | 19 | 16 |
| 批量赋值 / 过度提交 · 原型污染 | 915, 1321 | 18 | 16 |
| 暴力破解 · 缺少速率限制 · 资源耗尽 | 307, 400, 406, 674, 770 | 17 | 11 |
| 业务逻辑、定价和配额滥用 | 625, 840 | 15 | 14 |
| OS 命令 / 参数注入 | 78 | 14 | 12 |
| 不安全反序列化(pickle · PHP · Java · YAML) | 470, 502 | 14 | 11 |
| CORS 配置错误 | 942 | 14 | 14 |
| 竞态条件 / TOCTOU | 362 | 14 | 14 |
| 开放重定向 | 601 | 14 | 14 |
| 用户与资源枚举(可观察的响应差异) | 204, 598 | 13 |
按 OWASP 类别(Web 应用使用 2021 Top 10,仅 API 的应用使用 API Top 10 2023):
| OWASP | 漏洞数 | OWASP API | 漏洞数 | |
|---|---|---|---|---|
| A01 访问控制失效 | 118 | API8 安全配置错误 | 21 | |
| A03 注入 | 89 | API5 功能级授权失效 | 6 | |
| A05 安全配置错误 | 72 | API1 对象级/属性级授权失效 | 4 | |
| A07 身份识别与认证失败 | 65 | API2 认证失效 | 4 | |
| A04 不安全设计 | 34 | API7 服务端请求伪造 | 4 | |
| A08 软件与数据完整性失效 | 17 | API9 库存管理不当 | 3 | |
| A10 SSRF | 15 | API3 对象属性级授权失效 | 2 | |
| A02 加密失败 | 15 | API4 不受限制的资源消耗 | 2 | |
| A09 日志与监控失效 | 4 | API6 对敏感业务流的无限制访问 | 1 | |
| A06 易受攻击与过时的组件 | 3 | API10 不安全的 API 消费 | 1 |
两条非 Web 轨道与上述内容并列:network 应用为网络扫描器植入了 32 个主机/端口
和服务级发现,两个 LLM 应用
(llmchat、llmagent)植入了提示注入、工具滥用和 RAG 投毒漏洞,
在单独的注入通道轨道上进行评分。
每个漏洞还带有检测难度标签(118 个 E、68 个 E-M、202
个 M、61 个 M-H、100 个 H)、污点距离标签(351 个 文件内、83 个 跨文件、87
个 跨服务、28 个 配置)以及可达性标签(368 个 预认证、181
个 用户),因此召回率可以沿这些轴中的每一个进行细分,而不是
报告为单一数字。每个应用的目录位于
benchmark-plans/ 中。
dynast-bench/
├── README.md # you are here - overview, safety, run/score guide
├── examples/ # ready-to-score findings/v1 + endpoints/v1 files
├── Makefile # top-level runner: list / run / verify / validate / solo any app
├── benchmark-plans/ # per-stack design docs (the vulnerability catalogs)
├── dynast-bench/ # the dynast-bench CLI + scorer (Bun/TS)
└── vulnerable-apps/ # the 19 apps - each a separated, self-contained folder
├── _template/ # skeleton; copy it to start a new app
├── fastapi/ golang/ nextjs/ nestjs/ springboot/
└── rails/ wordpress/ php/ jsp/ aspnet/ ...
## 运行应用(`dynast-bench` CLI)
CLI 是驱动该套件最简单的方式——它对启动进行健康检查,仲裁共享端口,并支持 `--json` 输出,以便扫描器框架可以消费其结果。
需要 [Bun](https://bun.sh) 1.2+ 和 Docker。```bash
make install # compile the CLI + link it into ~/.bun/bin
# (BIN_DIR=/somewhere/else to pick the dir)
dynast-bench list # every app: vulns, PoCs, near-misses, what's up
dynast-bench vulns nextjs # the planted bugs as a checklist, one title each
# (--full · --near · --ids for a coverage diff)
dynast-bench start nextjs # build + boot, wait for health, print the URL
dynast-bench verify nextjs # run the ground-truth PoCs (expect all exploitable)
dynast-bench validate nextjs # twin loop: vuln all-exploitable → safe all-fixed
dynast-bench status # variant, mode, target, health
dynast-bench stop --all # stop everything
dynast-bench clean --all --images --yes # reclaim containers, volumes, networks, images
dynast-bench start nextjs --variant safe # the patched twin (false-positive run)
dynast-bench start --count 5 --parallel # 5 apps at once, one port each + a summary table
dynast-bench start --all --solo --parallel # whole fleet, one image + port each
dynast-bench run nextjs -- my-scanner --url '$TARGET' # start → scan → stop
完整参考:dynast-bench/README.md。
所有内容都位于临时端口范围中一个安静的切片内,因此该套件不会与常见的 3000/8000/8080/5432 端口冲突——并且每个应用都拥有一个固定端口,因此一个 URL 始终指向同一个应用,无论是单独运行还是五个一批运行:
| 范围 | 用途 |
|---|---|
13311–13339 | 被测应用——你指向扫描器的 URL,按 list 顺序每个应用一个端口(aspnet 13311、fastapi 13312、…… nextjs 13322) |
13340–13484 | 该应用的辅助服务(mailpit、phpMyAdmin、Jenkins、Prometheus、……),每个应用 5 个 |
13500–13599 | 迁移池 |
dynast-bench list 就是地图。如果某个应用拥有的端口上已有服务在监听,dynast-bench start 会跳过该端口,并从迁移池中发布该服务,然后打印(并通过 --json 报告)真实的 URL。任何内容都不会绑定到 127.0.0.1 之外。dynast-bench doctor 会显示哪些应用端口是空闲的;make 目标不会迁移,而是逐个发布 compose 默认端口(13311+),并遵循 DYNAST_PORT=<n>;--port N 可固定端口。
Makefile 仍然是底层契约,可独立运行:```bash make list # show all apps (a [solo] tag = has a single-image build) make run APP=nextjs # start via compose (app + datastores) make verify APP=nextjs # run its ground-truth PoCs (expect all exploitable) make validate APP=nextjs # full twin loop: vuln all-pass -> safe all-fixed make down APP=nextjs # stop it make solo APP=nextjs # run as ONE self-contained image - no compose needed make solo-down APP=nextjs # stop the standalone image
每个应用都有两种运行方式:
- **Compose**(`make run`)——规范的多服务拓扑,即基准测试目标所针对的环境(应用 + Postgres/Redis 等作为独立容器)。
- **Standalone**(`make solo`)——每个应用一个自包含镜像(`vuln/Dockerfile.standalone`),数据存储和内部 SSRF 接收端都嵌入其中,因此无需 compose 即可直接 `docker build` + `docker run`。行为和 PoC 完全相同(compose 服务名称会别名为 `127.0.0.1`)。
根目录刻意保持精简:本 README、设计指南、共享工具和应用。某个应用的所有运维相关内容都放在该应用自己的文件夹内。
## 每个应用的内部结构
`vulnerable-apps/` 下的每个应用都具有完全相同的结构:```
vulnerable-apps/<stack>/
├── README.md # LOUD banner + run notes
├── Makefile # up · reset · safe · verify · score · diff (uniform interface)
├── vuln/ # the vulnerable variant - this is what you scan by default
│ ├── docker-compose.yml # independent; binds 127.0.0.1 only
│ ├── app/ # application source; the planted bugs live here
│ └── db/seed.sql # seed incl. a cross-tenant user + a weak default cred
├── safe/ # the patched twin - same app, every planted bug fixed
│ ├── docker-compose.yml
│ ├── app/
│ └── db/seed.sql
└── ground-truth/ # the answer key - see "Ground truth" below
├── VULNERABILITIES.yaml # every planted bug
├── SURFACE.yaml # every endpoint the app exposes
├── verify/ # one runnable PoC per bug
└── expected/ # optional golden normalized findings
每个应用都附带两个独立的变体文件夹,而非使用 Git 分支或补丁文件:
vuln/ - 包含所有植入缺陷的应用。默认目标;扫描器指向的对象。safe/ - 相同的应用,但所有植入缺陷均已修复,且除此之外没有任何改动(参数化查询、转义输出、添加授权、安全反序列化器等)。diff -ru vulnerable-apps/<stack>/vuln vulnerable-apps/<stack>/safe 是基准真相。 它必须只触及 ground-truth/VULNERABILITIES.yaml 中列出的那些行,且不得改动其他任何内容。扫描 safe/ 变体可衡量工具的误报率:该变体中的每条发现都是误报,因为孪生应用在构造上就是干净的。
由于每个变体的 Docker 构建上下文是其各自的文件夹(vuln/ 或 safe/),应用的 ground-truth/ 位于所有构建上下文之外,因此无法被烘焙进镜像——答案密钥在构造上不可能泄露到运行中的应用中。
ground-truth/)有两份答案密钥,因为有两个问题。VULNERABILITIES.yaml 说明应用中哪里有问题;SURFACE.yaml 说明应用中存在什么。
VULNERABILITIES.yaml 为每个植入缺陷记录一条条目:```yaml
`SURFACE.yaml` 记录应用所暴露的**每个操作**一条条目,无论其存在漏洞还是良性——它是[端点覆盖率](#endpoint-coverage)的分母:```yaml
operations:
- id: posts.search
kind: http # http | graphql | ws | llm | net
method: GET
path: /api/posts/search
params: [q]
discovery: js-runtime # same crawl tiers as the answer key
reachability: user
vulns: [SQLI-001] # omit when the operation is benign
- id: graphql.mutation.update-post
kind: graphql # the op BEHIND POST /graphql, which is its own entry
op: updatePost
graphql_kind: mutation
via: graphql.transport
discovery: static-html
良性操作是有意包含在内的:如果只收录易受攻击的路由,那么衡量的是答案键的覆盖率,而不是应用的覆盖率。
verify/ 目录中每个漏洞对应一个可运行的 PoC——它针对 vuln/ 退出码为 0,而针对 safe/ 退出码非零。这就是“漏洞是真实的(并且在孪生版本中确实已修复)”的可执行定义。
共享运行器(dynast-bench/tools/poc-runner.sh)增加了退出码本身无法承载的第三种结果:测试框架无法运行。如果将测试套件指向一个没有服务监听的端口,那么任何应用中相当一部分 PoC 都会以 1 退出——这与真正的修复无法区分。因此,运行器在采信拒绝结果之前会先对目标进行健康探测,为每个 PoC 设置截止时间,并在超时、缺少工具或目标停止响应时判定两条测试腿均失败。“测试套件无法运行”绝不会被记录为“漏洞已修复”。
dynast-bench/,Bun/TypeScript)一套工具链,供每个应用使用,以确保跨技术栈的结果具有可比性:
dynast-bench.ts —— CLI:启动/停止/重置/清理、健康门控、端口仲裁、PoC 验证、评分,以及供测试框架使用的 --json。src/schema/ —— 两种报告格式(findings/v1、endpoints/v1)和两种答案键(VULNERABILITIES.yaml、SURFACE.yaml)的类型与验证器、用于部分得分的 CWE 家族表,以及比较双方都会经过的路径/路由/操作归一化器。src/normalize/ —— 将原始扫描器输出(OWASP ZAP、来自 Semgrep/CodeQL/Snyk 的 SARIF、nuclei、Burp XML、nmap XML)转换为该格式的适配器。格式会自动检测,因此 score 可直接接受原生输出。src/scorer/ —— 将发现结果与答案键进行匹配,并输出精确率 / 召回率 / F1、按难度/严重性/可达性/污点/CWE 划分的召回率、针对近似命中的区分度得分,以及重复(噪声)比率。此外,端点覆盖率 轨道会评估一次运行实际触及了多少应用,并将每个漏报拆分为“从未找到端点”与“找到了端点但漏掉了漏洞”。```
dynast-bench verify # run the app's ground-truth PoCs
dynast-bench score findings.json # findings → P/R/F1 + per-dimension recall
dynast-bench coverage endpoints.json # endpoint discovery → how much was reached
dynast-bench surface # the operation checklist a crawl is graded on
dynast-bench diff # the vuln↔safe delta vs the answer key
dynast-bench check --all # CI gate: schema · anchors · diff scope · binds[`examples/`](https://github.com/j3ssie/dynast-bench/blob/HEAD/examples/) 目录中存放着您可以立即评分的文件——一份发现结果运行、一份误报运行、三条端点追踪记录以及两份空白模板,每个文件都附有文档说明其生成的数字:```bash
dynast-bench score nextjs examples/findings.json --safe examples/findings-safe.json
dynast-bench coverage nextjs examples/endpoints.json --findings examples/findings.json
完整参考——发现模式、匹配层级、每项指标:
dynast-bench/README.md。
make up # docker compose up the vuln/ variant (127.0.0.1 only), wait for health make reset # down -v && up → fresh, byte-identical state make safe # bring up the safe/ variant instead (for false-positive runs) make verify # run every ground-truth PoC; expect all PASS against vuln/ make score FINDINGS=f.json # grade a scanner's findings → P/R/F1 make diff # the vuln↔safe delta, cross-checked against the answer key make check # CI gate: schema · anchors · diff scope · PoCs · 127.0.0.1 binds
## 应用
| 应用 | 技术栈 | 数据库 | 附加服务 | 设计文档 |
|------------|--------------------------------|------------|----------------------|------------|
| fastapi | Python / FastAPI + Jinja2 | Postgres | MinIO, Mailpit | [fastapi.md](https://github.com/j3ssie/dynast-bench/blob/HEAD/benchmark-plans/fastapi.md) |
| golang | Go / chi | Postgres | Prometheus, Grafana | [golang.md](https://github.com/j3ssie/dynast-bench/blob/HEAD/benchmark-plans/golang.md) |
| gin | Go / Gin | Postgres | chromium, ImageMagick(镜像内) | [README](https://github.com/j3ssie/dynast-bench/blob/HEAD/vulnerable-apps/gin/README.md) |
| nextjs | Node / Next.js 15 | Postgres | Redis, Mailpit | [nextjs.md](https://github.com/j3ssie/dynast-bench/blob/HEAD/benchmark-plans/nextjs.md) |
| nestjs | Node / NestJS + Handlebars | Postgres | Redis, nginx | [nestjs.md](https://github.com/j3ssie/dynast-bench/blob/HEAD/benchmark-plans/nestjs.md) |
| springboot | Java / Spring Boot + Thymeleaf | Postgres | Jenkins, Prometheus | [springboot.md](https://github.com/j3ssie/dynast-bench/blob/HEAD/benchmark-plans/springboot.md) |
| rails | Ruby / Rails 7.2 | Postgres | MinIO, nginx | [rails.md](https://github.com/j3ssie/dynast-bench/blob/HEAD/benchmark-plans/rails.md) |
| wordpress | PHP / WordPress + 插件 | MySQL | nginx, Mailpit | [wordpress.md](https://github.com/j3ssie/dynast-bench/blob/HEAD/benchmark-plans/wordpress.md) |
| php | PHP / 过程式 LAMP | MySQL | phpMyAdmin, Mailpit | [php.md](https://github.com/j3ssie/dynast-bench/blob/HEAD/benchmark-plans/php.md) |
| jsp | Java / JSP + Servlets (Tomcat) | Postgres | Mailpit | [jsp.md](https://github.com/j3ssie/dynast-bench/blob/HEAD/benchmark-plans/jsp.md) |
| aspnet | C# / ASP.NET Core Razor Pages | SQL Server | Mailpit | [aspnet.md](https://github.com/j3ssie/dynast-bench/blob/HEAD/benchmark-plans/aspnet.md) |
另有三个**仅 API** 应用(GraphQL、WebSocket、Swagger/OpenAPI)、一个用于主机/端口扫描器的**网络范围**集群,以及两个 **LLM** 应用:
| 应用 | 技术栈 | 数据库 | 附加服务 | 设计文档 |
|------------|---------------------------------------------|-------------------|--------------------------------------|------------|
| llmchat | Python / FastAPI + LangChain(RAG 聊天机器人) | Postgres+pgvector | Redis, Ollama, 内部服务 | [llmchat.md](https://github.com/j3ssie/dynast-bench/blob/HEAD/benchmark-plans/llmchat.md) |
| llmagent | Node / Fastify + Vercel AI SDK + MCP(代理)| Postgres | Redis, Ollama, partner-MCP, 内部服务 | [llmagent.md](https://github.com/j3ssie/dynast-bench/blob/HEAD/benchmark-plans/llmagent.md) |
两个 LLM 应用均通过仅内部访问的 Ollama 容器运行**本地模型**
(聊天用 `gemma3:1b`,工具调用用 `qwen2.5:1.5b`)——无需 API 密钥、无出站流量、
无按次运行成本——并附带脚本化的 `LLM_BACKEND=stub` 后端,使
基准事实 PoC 在随机模型下仍保持确定性。
共享领域模型、OWASP Top 10 覆盖矩阵以及基准设计
原则(近似命中、污点距离、仅逻辑缺陷)请参阅
[`benchmark-plans/README.md`](https://github.com/j3ssie/dynast-bench/blob/HEAD/benchmark-plans/README.md)。
## 快速开始```bash
make install # once: puts `dynast-bench` on your PATH
dynast-bench doctor # docker reachable? which ports are taken?
dynast-bench start fastapi # boots the vuln/ variant, waits for health
dynast-bench verify fastapi # sanity-check: every planted bug's PoC PASSes
# ...point your scanner/agent at $(dynast-bench target fastapi), collect findings.json...
dynast-bench start fastapi --variant safe # patched twin → measures false positives
dynast-bench reset fastapi # restore fresh, re-seeded state
dynast-bench clean --all --yes # give the disk back
直接使用其 Makefile 驱动一个应用:```bash cd vulnerable-apps/fastapi make up # vuln/ variant on 127.0.0.1 make verify # every planted bug's PoC PASSes make safe # the patched twin make reset # fresh state
## 状态
- **19 个应用带有完整答案密钥**:549 个植入漏洞、146 个
接近命中、546 个 PoC,以及每个应用一个 `Dockerfile.standalone`(`--solo`)。
`dynast-bench list` 会打印实时表格。
- **`nextjs` 是参考实现**——已端到端构建并验证
(35 个漏洞 + 15 个接近命中)。`make validate APP=nextjs` 证明每个 PoC
在 `vuln/` 上可利用、在 `safe/` 上已修复;`make solo APP=nextjs` 从
单个镜像运行它。复制其模式。
- **`dynast-bench` CLI——已构建**:可运行、验证、评分并清理任何应用,
支持 compose 或单镜像模式,并提供 `--json` 供测试框架使用。
- **评分器——已构建**(`dynast-bench/src/`):扫描器输出 → 规范化发现
→ 精确率/召回率/F1、按难度划分的召回率、针对
接近命中的区分度分数,以及独立的发现(网络)和注入通道(LLM)跟踪。
- **端点覆盖率——已构建**:每个应用一个 `SURFACE.yaml`(整个
集群约 600 个操作),用于评估一次运行实际触及了应用的多少部分,
并将每次遗漏拆分为“从未找到端点”与“找到了端点但遗漏了漏洞”。
- 针对全部 19 个答案密钥和表面目录的每个应用不变量在
`make test` 中运行;`dynast-bench check --all` 是 CI 门禁。
## 对工具进行评分```bash
dynast-bench start nextjs --json | jq -r .target # boot, get the URL
zap-baseline.py -t http://127.0.0.1:13311 -J zap.json # scan
dynast-bench score nextjs zap.json --full # grade it
# measure false positives properly: scan the patched twin too
dynast-bench start nextjs --variant safe
my-scanner --url http://127.0.0.1:13311 --out safe.json
dynast-bench score nextjs zap.json --safe safe.json
score 读取 findings/v1 文件或原生 ZAP / SARIF / nuclei / Burp / nmap
输出——格式会被自动嗅探。如果你正在接入某个工具,请从 examples/ 开始:
examples/template-findings.json 是一个包含所有字段的空白骨架,
而 examples/findings.json 是一个现在就可以直接评分的可用文件。
端点发现会单独评分,依据每个应用的 SURFACE.yaml 进行:```bash
dynast-bench coverage nextjs endpoints.json --findings findings.json
这就是**发现遗漏**(从未到达端点——修复爬虫)与**分析遗漏**(已到达端点,但未报告——修复扫描器)之间的区别。有关模式、匹配层级及每项指标,请参阅 [`dynast-bench/README.md`](https://github.com/j3ssie/dynast-bench/blob/HEAD/dynast-bench/README.md#scoring)。
### 阅读报告(`Leg │ Precision │ Recall │ F1`)
**leg(扫描腿)** 是针对一个目标状态执行的一次扫描运行:
| Leg | 含义 |
|---|---|
| `blackbox` | 无凭据——未认证攻击者的视角 |
| `credentialed` | 同一目标,但注入了预置登录凭据,因此可触达已认证的攻击面(IDOR、权限提升) |
| `safe-twin` | 已修补的孪生目标(`--safe`),作为误报基线——理想情况下不应发现任何内容 |
三者均以 `0.0`–`1.0` 计分,且对三者而言**越高越好**(`1.0` 为完美):
| 指标 | 公式 | 越好 | 解读 |
|---|---|---|---|
| **Precision(精确率)** | `TP / (TP + FP)` | ↑ 越高 | 在所有报告的内容中,有多少是真实的。`0.38` = 约 38% 的发现是真实的,其余为噪声。高值 = 误报少。 |
| **Recall(召回率)** | `TP / (TP + FN)` | ↑ 越高 | 在实际植入的漏洞中,有多少被发现。`0.73` = 11 个中发现了 8 个。高值 = 遗漏少。 |
| **F1** | `2 × P × R / (P + R)` | ↑ 越高 | 两者的调和平均值——即“整体质量”的核心指标。只有当两者都高时才会高,因此它会同时惩罚噪声大和遗漏漏洞的情况。 |
唯一例外:在 **`safe-twin` 扫描腿上没有任何真实内容可发现**,因此该腿上的每个发现都是误报——越少越好,空报告即为满分。
## 端点覆盖率
召回率告诉你工具发现了多少个漏洞,但它无法告诉你**为什么**遗漏了其余部分——而这两种原因需要相反的修复方式:
| 遗漏 | 含义 | 需修复的内容 |
|---|---|---|
| **发现遗漏** | 从未到达承载漏洞的端点 | 爬虫 |
| **分析遗漏** | 已到达端点,但未报告漏洞 | 分析逻辑 |
要区分两者,需要第二个输入:你的工具声称发现的端点。这就是 `endpoints/v1`,它会针对每个应用的 `SURFACE.yaml` 进行评分。```bash
dynast-bench surface nextjs # the checklist a crawl is graded on
dynast-bench coverage nextjs endpoints.json # how much did it reach?
dynast-bench coverage nextjs endpoints.json --findings findings.json # ...and why not the rest
dynast-bench score nextjs findings.json --endpoints endpoints.json # both in one report
一个能读取HTML并运行JS,但从不完成多步骤流程的爬虫:``` operations 62.5% 25 of 40 detection 25.0% of the bugs on operations it reached misses: 11 never reached the operation · 18 reached it and did not report
static-html 6/6 100.0% js-static 5/5 100.0% js-runtime 11/19 57.9% interaction 3/5 60.0% flow 0/5 0.0%
层级划分才是最有价值的部分:`static-html` 上 100% 而 `flow` 上 0% 是发现层面的问题,而非扫描器的问题,而这两者在单一召回数字中看起来完全相同。
两条规则确保该数字保持真实:
- **传输不等于操作。** 一次 `POST /graphql` 并不会执行其背后的 25 个 GraphQL 操作;一次 WebSocket 握手并不会执行其事件;一次 `POST /api/runs` 并不会执行代理的工具。访问一个 URL 与执行该 URL 上承载的内容是分别评分的。
- **缺失的遥测不会产生任何轨迹**,绝不会是 `0%`。“我们没有测量到这一点”和“它没有触达任何内容”是对工具截然相反的两种论断。
报告出的端点若与任何内容都不匹配,会降低精确度,但绝不会减少覆盖率,因此喷洒字典并非提高分数的途径。完整模型见:
[`dynast-bench/README.md#endpoint-coverage`](https://github.com/j3ssie/dynast-bench/blob/HEAD/dynast-bench/README.md#endpoint-coverage)。
## 许可证
`dynast-bench` 由 [@j3ssie](https://github.com/j3ssie) 倾心打造,用于对
**Vigolium** 和 **Gimora**(一款自主进攻性安全代理)进行基准测试,并以
[MIT 许可证](https://github.com/j3ssie/dynast-bench/blob/HEAD/LICENSE) 发布。
| llmagent | Node / Fastify + AI SDK + MCP | Postgres | 29 | 8 | 计划 |
| llmchat | Python / FastAPI + LangChain RAG | Postgres+pgvector | 30 | 9 | 计划 |
| nestjs | Node / NestJS + Handlebars | Postgres | 23 | 6 | 计划 |
| network | 模拟多主机网络范围 | 混合机群 | 32 | 5 | 计划 |
| nextjs | Node / Next.js 15 (参考实现) | Postgres | 35 | 15 | 计划 |
| php | PHP / 过程式 LAMP | MySQL | 21 | 5 | 计划 |
| rails | Ruby / Rails 7.2 | Postgres | 26 | 6 | 计划 |
| springboot | Java / Spring Boot + Thymeleaf | Postgres | 30 | 4 | 计划 |
| swagger | OpenAPI / Swagger UI + 规范加载 | Postgres | 19 | 5 | 计划 |
| websocket | Node 22 / ws + Socket.IO 实时 | Postgres | 28 | 6 | 计划 |
| weirdproxy | nginx + Apache + Traefik 位于单一源之上 | 无 | 16 | 4 | 计划 |
| wordpress | PHP / WordPress + 自定义插件 | MySQL | 28 | 6 | 计划 |
| 12 |
| 代码注入 · SSTI · 表达式语言 | 94, 917, 1059, 1336 | 11 | 10 |
| 弱加密与随机性 · 明文传输 | 295, 319, 327, 330, 338 | 11 | 6 |
| 密码重置 + 账户恢复缺陷 | 184, 640 | 9 | 9 |
| 不受限制 / 不安全的文件上传 | 434 | 9 | 9 |
| CSRF(包括跨站 WebSocket 劫持) | 352 | 8 | 8 |
| 提示注入与 LLM 工具滥用(直接 · 间接 · RAG) | 1427 | 7 | 2 |
| XXE / XML 外部实体 | 611 | 5 | 5 |
| 供应链与完整性(未签名更新、易受攻击的依赖) | 494, 1035 | 2 | 2 |
| 不安全的网络暴露(绑定、服务配置错误) | 1327 | 2 | 1 |
| 日志记录不足 / 日志注入 | 117 | 1 | 1 |