
意図的に脆弱性を含むアプリ群を対象としたDASTベンチマークで、スキャナーのスコアリング用に正解キーを備えています。
意図的に脆弱性を含むアプリを対象としたDASTベンチマーク。スキャナのスコアリング用に正解キー(ground-truth)を備えています。
⚠️ このリポジトリには、意図的に安全でないアプリケーションが含まれています。 これらは セキュリティツール(DASTスキャナ、SASTエンジン、LLMセキュリティエージェント)のベンチマークのみを目的として存在します。 すべてのアプリは
127.0.0.1にバインドされ、目立つバナーを表示し、 実際のデータは保持しません。これらのいずれも公開ネットワーク上にデプロイしないでください。
19個の意図的に脆弱性を含むアプリのスイートで、スタックごとに1つずつあり、それぞれに文書化され、 機械で検証可能な正解(ground truth) が付属しています。目的は、スキャナまたはエージェントが (a) 仕込まれたバグをどれだけ見つけられるか、(b) そのすぐ隣にある安全なニアミスコードを無視できるか、 (c) パッチ適用済みの双子に対して誤検知(幻覚)を出さないかを測定することです。
19アプリ・549件の仕込まれた脆弱性・146件のニアミス・546件の実行可能なPoC・594件のカタログ化されたエンドポイント。
すべてのアプリは127.0.0.1:13311で起動し、vuln/+safe/の双子ペアと単一イメージの--soloビルドを提供します。
dynast-bench listはこの表をライブで表示し、dynast-bench surface <app>はエンドポイントカタログを表示します。
| App | Stack | Datastore | Vulns | Near-miss | Docs |
|---|---|---|---|---|---|
| aspnet | C# / ASP.NET Core Razor Pages | SQL Server | 28 | 12 | plan |
| fastapi | Python / FastAPI + Jinja2 | Postgres | 26 | 5 | plan |
| gin | Go / Gin | Postgres | 12 | 7 | readme |
| golang | Go / chi | Postgres | 26 | 4 | plan |
| graphql | Node / GraphQL 16 API-only | Postgres | 31 | 6 | plan |
| jsp | Java / JSP + Servlets (Tomcat) | Postgres | 28 | 6 | plan |
| laravel | PHP 8.3 / Laravel 11 + Blade | MySQL | 25 | 7 | plan |
スタックごとの追加サイドカー(Mailpit、MinIO、Redis、Jenkins、Prometheus、Ollamaなど)は 下記のThe appsに一覧されています。
スタックごとの設計ドキュメントはbenchmark-plans/にあります -
各アプリの完全な脆弱性カタログはそこから始めてください。このREADMEは運用ガイドです:
リポジトリの構成方法と、アプリの実行方法・スコアリング方法について説明します。
仕込まれたすべてのバグにはCWEとOWASPカテゴリが付与されています。クラス別に集計すると (各バグはプライマリCWEの下で1回だけカウント)、仕込まれたバグはおおよそ次のように分類されます (ロールアップは480バグ時点で最後に再生成されました。上記のアプリごとの数値は最新です):
| Class | CWEs | Bugs | Apps |
|---|---|---|---|
| Sensitive data exposure (errors, logs, debug endpoints, backups, source) | 200, 209, 489, 524, 532, 538, 540, 548 | 39 | 16 |
| Default / hardcoded / leaked credentials | 321, 522, 798, 1104, 1392 | 38 | 18 |
| Missing or broken authorization (BFLA, vertical + horizontal) | 269, 284, 285, 668, 862, 863 | 37 | 18 |
| Cross-site scripting (reflected · stored · DOM) | 79 | 28 | 16 |
| Authentication bypass · weak session · JWT verification | 287, 288, 290, 306, 347, 384, 613, 614, 1385 | 28 | 13 |
| SQL injection (incl. second-order, ORDER BY, NoSQL) | 89, 943 | 27 | 17 |
| Proxy / parser interpretation conflicts (path confusion, header trust) | 345, 348, 349, 436, 441, 693, 697, 706, 807 | 27 | 10 |
| SSRF (incl. blind, redirect chains, internal-only sinks) | 918 | 20 | 17 |
| IDOR / BOLA (user-controlled object key) | 639 | 19 | 17 |
| Path traversal · LFI/RFI · zip slip | 22, 98 | 19 | 16 |
| Mass assignment / over-posting · prototype pollution | 915, 1321 | 18 | 16 |
| Brute force · missing rate limiting · resource exhaustion | 307, 400, 406, 674, 770 | 17 | 11 |
| Business-logic, pricing and quota abuse | 625, 840 | 15 | 14 |
| OS command / argument injection | 78 | 14 | 12 |
| Insecure deserialization (pickle · PHP · Java · YAML) | 470, 502 | 14 | 11 |
| CORS misconfiguration | 942 | 14 |
OWASPカテゴリ別(Webアプリには2021 Top 10、APIのみのアプリにはAPI Top 10 2023):
| OWASP | Bugs | OWASP API | Bugs | |
|---|---|---|---|---|
| A01 Broken Access Control | 118 | API8 Security Misconfiguration | 21 | |
| A03 Injection | 89 | API5 Broken Function Level Authorization | 6 | |
| A05 Security Misconfiguration | 72 | API1 Broken Object Level/Property Authorization | 4 | |
| A07 Identification & Authentication Failures | 65 | API2 Broken Authentication | 4 | |
| A04 Insecure Design | 34 | API7 Server Side Request Forgery | 4 | |
| A08 Software & Data Integrity Failures | 17 | API9 Improper Inventory Management | 3 | |
| A10 SSRF | 15 | API3 Broken Object Property Level Authorization | 2 | |
| A02 Cryptographic Failures | 15 | API4 Unrestricted Resource Consumption | 2 | |
| A09 Logging & Monitoring Failures | 4 | API6 Unrestricted Access to Sensitive Business Flows | 1 | |
| A06 Vulnerable & Outdated Components | 3 | API10 Unsafe Consumption of APIs | 1 |
これらに並んで、2つの非Webトラックがあります:networkアプリはネットワークスキャナ向けに
32件のホスト/ポートおよびサービスレベルの検出結果を仕込み、2つのLLMアプリ
(llmchat、llmagent)はプロンプトインジェクション、ツール悪用、RAGポイズニングのバグを仕込み、
これらは別のインジェクションチャネルトラックでスコアリングされます。
各バグにはさらに検出難易度(118 E、68 E-M、202 M、61 M-H、100 H)、
汚染距離(taint distance)(351 in-file、83 cross-file、87 cross-service、28 config)、
到達可能性(reachability)(368 pre-auth、181 user)がタグ付けされているため、
再現率(recall)を単一の数値として報告する代わりに、これらの各軸に沿って分解できます。
アプリごとのカタログは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
Full reference: dynast-bench/README.md。
すべては一時的なレンジの静かなスライスに存在するため、スイートは通常の3000/8000/8080/5432の群れと競合しません。そしてすべてのアプリは固定ポートを所有しているため、URLは常に同じアプリを意味します。単独でも5つのバッチでも同様です:
| レンジ | 内容 |
|---|---|
13311–13339 | テスト対象のアプリ - スキャナを向けるURL。listの順序でアプリごとに1ポート(aspnet 13311、fastapi 13312、… nextjs 13322) |
13340–13484 | そのアプリのサイドカー(mailpit、phpMyAdmin、Jenkins、Prometheus、…)、各5つ |
13500–13599 | 再配置プール |
dynast-bench listがマップです。アプリが所有するポートで既に何かがリッスンしている場合、dynast-bench startはそれをそのままにし、代わりに再配置プールからその1つのサービスを公開し、実際のURLを出力(および--jsonで報告)します。127.0.0.1を超えてバインドされることは決してありません。dynast-bench doctorはどのアプリポートが空いているかを示します。makeターゲットは再配置せず、composeのデフォルト(13311+)を一度に1アプリずつ公開し、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
Two ways to run every app:
- **Compose** (`make run`) - the canonical multi-service topology the ground
truth targets (app + Postgres/Redis/etc. as separate containers).
- **Standalone** (`make solo`) - one self-contained image per app
(`vuln/Dockerfile.standalone`) with the datastores + an internal SSRF sink
embedded, so `docker build` + `docker run` works with no compose. Behaviour
and PoCs are identical (compose service names are aliased to `127.0.0.1`).
The root stays deliberately small: this README, the design guide, the shared
tooling, and the apps. Everything operational for a given app is inside that
app's own folder.
## Per-app anatomy
Every app under `vulnerable-apps/` has the identical shape:```
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ブランチやパッチファイルではなく、2つの分離されたバリアントフォルダが同梱されています:
vuln/ - 植え付けられたすべてのバグを含むアプリ。デフォルトのターゲットであり、スキャナが指し示す対象です。safe/ - 植え付けられたすべてのバグが修正され、それ以外は何も変更されていない同じアプリ(パラメータ化クエリ、エスケープされた出力、追加された認可、安全なデシリアライザなど)。diff -ru vulnerable-apps/<stack>/vuln vulnerable-apps/<stack>/safe が真実の基準です。 これは、ground-truth/VULNERABILITIES.yaml に記載されている行のみに正確に触れ、それ以外には触れてはなりません。safe/ バリアントのスキャンは、ツールの誤検知率を測定します。そこでのすべての検出は誤警報です。なぜなら、双子は構造上クリーンだからです。
各バリアントのDocker ビルドコンテキストは独自のフォルダ(vuln/ または safe/)であるため、アプリの ground-truth/ はすべてのビルドコンテキストの外側に位置し、イメージに焼き込むことはできません。つまり、構造上、解答キーが実行中のアプリに漏れることはありません。
ground-truth/)2つの質問があるため、2つの解答キーがあります。VULNERABILITIES.yaml はアプリ内で何が間違っているかを示し、SURFACE.yaml は何が存在するかを示します。
VULNERABILITIES.yaml は、植え付けられたバグごとに1つのエントリを記録します:```yaml
`SURFACE.yaml` には、**アプリが公開する操作**ごとに1つのエントリが記録されます。脆弱な操作も良性の操作も同様に含まれ、これは[エンドポイントカバレッジ](#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が1つずつ入っており、vuln/ に対しては0で終了し、safe/ に対しては非ゼロで終了する。これが「バグは実在する(そして双子では実際に修正されている)」という実行可能な定義である。
共有ランナー(dynast-bench/tools/poc-runner.sh)は、終了コードだけでは伝えられない3つ目の結果を追加する。ハーネスが実行できなかったというものだ。スイートを何も待ち受けていないポートに向けると、どのアプリのPoCでも半分近くが1で終了する——これは本物の修正と区別がつかない。そこでランナーは、拒否を信じる前にターゲットをヘルスプローブし、PoCごとの期限を適用し、タイムアウト、ツールの欠落、応答を停止したターゲットのいずれかで両方のレグを失敗させる。「スイートが実行できなかった」が「脆弱性が修正された」として記録されることは決してない。
dynast-bench/、Bun/TypeScript)すべてのアプリで使用される単一のツールチェーン。これにより、スタックをまたいだ結果が比較可能になる。
dynast-bench.ts — CLI:起動/停止/リセット/クリーン、ヘルスゲーティング、ポート調停、PoC検証、スコアリング、ハーネス向けの--json。src/schema/ — 2つのレポート形式(findings/v1、endpoints/v1)と2つの解答キー(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/) には、すぐにスコアリングできるファイルが含まれています。検出結果の実行、誤検知の実行、3つのエンドポイントトレース、2つの空のテンプレートがあり、それぞれが生成する数値とともに文書化されています。```bash
dynast-bench score nextjs examples/findings.json --safe examples/findings-safe.json
dynast-bench coverage nextjs examples/endpoints.json --findings examples/findings.json
Full reference - the finding schema, the matching tiers, every metric:
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
## アプリ
| アプリ | スタック | DB | 追加サービス | 設計ドキュメント |
|------------|--------------------------------|------------|----------------------|------------|
| 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専用**アプリが3つ(GraphQL、WebSocket、Swagger/OpenAPI)、
ホスト/ポートスキャナ向けの**ネットワークレンジ**フリート、そして**LLM**アプリが2つあります:
| アプリ | スタック | DB | 追加サービス | 設計ドキュメント |
|------------|---------------------------------------------|-------------------|--------------------------------------|------------|
| llmchat | Python / FastAPI + LangChain (RAGチャットボット) | Postgres+pgvector | Redis, Ollama, 内部svc | [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, 内部svc | [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
Or drive one app directly with its 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/`): スキャナ出力 → 正規化された検出結果 → precision/recall/F1、難易度別のrecall、ニアミスに対する識別スコア、そして探索(ネットワーク)と注入チャネル(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
That is what separates a **discovery miss** (never reached the endpoint - fix the
crawler) from an **analysis miss** (reached it, did not report - fix the scanner).
See [`dynast-bench/README.md`](https://github.com/j3ssie/dynast-bench/blob/HEAD/dynast-bench/README.md#scoring) for the schema, the
matching tiers and every metric.
### Reading the report (`Leg │ Precision │ Recall │ F1`)
A **leg** is one scan run against one target state:
| Leg | What it is |
|---|---|
| `blackbox` | no credentials - the unauthenticated attacker view |
| `credentialed` | same target with the seeded logins injected, so authenticated surface (IDOR, privilege escalation) is reachable |
| `safe-twin` | the patched twin (`--safe`), a false-positive baseline - ideally finds nothing |
All three run `0.0`–`1.0`, and for all three **higher is better** (`1.0` is perfect):
| Metric | Formula | Better | Reads as |
|---|---|---|---|
| **Precision** | `TP / (TP + FP)` | ↑ higher | of everything reported, how much was real. `0.38` = ~38% of findings were genuine, the rest noise. High = few false alarms. |
| **Recall** | `TP / (TP + FN)` | ↑ higher | of the bugs actually planted, how many were found. `0.73` = 8 of 11. High = few misses. |
| **F1** | `2 × P × R / (P + R)` | ↑ higher | harmonic mean of the two - the headline "overall quality" number. Only high when both are, so it penalises being noisy *and* missing bugs. |
The one inversion: on the **`safe-twin` leg there is nothing real to find**, so
every finding there is a false alarm - fewer is better, and an empty report is
the perfect score.
## Endpoint coverage
Recall tells you how many bugs a tool found. It cannot tell you **why** it missed
the rest - and the two reasons need opposite fixes:
| Miss | Meaning | What to fix |
|---|---|---|
| **discovery miss** | never reached the endpoint carrying the bug | the crawler |
| **analysis miss** | reached the endpoint, did not report the bug | the analysis |
Telling them apart needs a second input: the endpoints your tool says it found.
That is `endpoints/v1`, scored against each app's `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%というのは、スキャナーの問題ではなく発見の問題であり、単一のリコール数値では両者は同じように読めてしまいます。
数値を正直に保つための2つのルールがあります:
- **トランスポートは操作ではない。** 1回の `POST /graphql` は、その背後にある25個のGraphQL操作を実行するものではありません。1回のWebSocketハンドシェイクは、そのイベントを実行するものではありません。1回の `POST /api/runs` は、エージェントのツールを実行するものではありません。URLに到達することと、そこに存在するものを実行することは、別々に採点されます。
- **欠落したテレメトリはトラックを一切生成せず**、決して `0%` にはなりません。「これを測定しなかった」と「何にも到達しなかった」は、ツールに関する正反対の主張です。
何にも一致しない報告済みエンドポイントは精度を低下させますが、カバレッジを減らすことは決してないため、ワードリストをばらまいてもスコアを上げる方法にはなりません。完全なモデル:
[`dynast-bench/README.md#endpoint-coverage`](https://github.com/j3ssie/dynast-bench/blob/HEAD/dynast-bench/README.md#endpoint-coverage)
## ライセンス
`dynast-bench` は、**Vigolium** と **Gimora**(自律型オフェンシブセキュリティエージェント)をベンチマークするために [@j3ssie](https://github.com/j3ssie) が ♥ を込めて作成したものであり、[MITライセンス](https://github.com/j3ssie/dynast-bench/blob/HEAD/LICENSE) の下でリリースされています。
| llmagent | Node / Fastify + AI SDK + MCP | Postgres | 29 | 8 | plan |
| llmchat | Python / FastAPI + LangChain RAG | Postgres+pgvector | 30 | 9 | plan |
| nestjs | Node / NestJS + Handlebars | Postgres | 23 | 6 | plan |
| network | Simulated multi-host network range | mixed fleet | 32 | 5 | plan |
| nextjs | Node / Next.js 15 (reference impl) | Postgres | 35 | 15 | plan |
| php | PHP / procedural LAMP | MySQL | 21 | 5 | plan |
| rails | Ruby / Rails 7.2 | Postgres | 26 | 6 | plan |
| springboot | Java / Spring Boot + Thymeleaf | Postgres | 30 | 4 | plan |
| swagger | OpenAPI / Swagger UI + spec loading | Postgres | 19 | 5 | plan |
| websocket | Node 22 / ws + Socket.IO realtime | Postgres | 28 | 6 | plan |
| weirdproxy | nginx + Apache + Traefik over one origin | none | 16 | 4 | plan |
| wordpress | PHP / WordPress + custom plugin | MySQL | 28 | 6 | plan |
| 14 |
| Race conditions / TOCTOU | 362 | 14 | 14 |
| Open redirect | 601 | 14 | 14 |
| User & resource enumeration (observable response discrepancy) | 204, 598 | 13 | 12 |
| Code injection · SSTI · expression language | 94, 917, 1059, 1336 | 11 | 10 |
| Weak crypto & randomness · cleartext transport | 295, 319, 327, 330, 338 | 11 | 6 |
| Password reset + account recovery flaws | 184, 640 | 9 | 9 |
| Unrestricted / unsafe file upload | 434 | 9 | 9 |
| CSRF (incl. cross-site WebSocket hijacking) | 352 | 8 | 8 |
| Prompt injection & LLM tool abuse (direct · indirect · RAG) | 1427 | 7 | 2 |
| XXE / XML external entity | 611 | 5 | 5 |
| Supply chain & integrity (unsigned updates, vulnerable deps) | 494, 1035 | 2 | 2 |
| Insecure network exposure (binding, service misconfiguration) | 1327 | 2 | 1 |
| Insufficient logging / log injection | 117 | 1 | 1 |