ZeroDOM について
ZeroDOMは、アプリケーションセキュリティチームやAIエージェント向けの決定論的なブラウザー・セキュリティテストエンジンです。実際のセッションを比較してアクセス制御の問題を見つけ、トークン消費を抑えたMCPインターフェースでブラウザー操作を提供します。
主な機能
- 012つのIDによるアクセス制御テスト
- 02アプリ全体の読み取り専用スイープ
- 03エンドポイントの再実行と応答差分
- 04マスアサインメントと競合状態の検査
- 05安定したブラウザー要素ハンドル
- 06トークン効率のよい操作グラフ
活用シーン
- 01ユーザー役割ごとのエンドポイントアクセス比較
- 02アプリをマッピングしてGET範囲を検査
- 03マスアサインメントやTOCTOUの疑いを検証
MCP 対応
ZeroDOMはMCPサーバーとして、AIエージェントにブラウザー操作とセキュリティテストのツールを提供します。repeat、probe、raceの操作も利用できます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
24掲載時のツール一覧 · 2 日前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| url | string | はい | |
| frames | boolean | いいえ | |
| verbose | boolean | いいえ | |
| viewport_only | boolean | いいえ | |
| check_occlusion | boolean | いいえ |
詳細
ZeroDOM
アプリを2人のユーザーとして指定するだけで、アクセス制御の不備を検出します。
実際にログインしたブラウザーを2つのIDとして操作し、それぞれで同じリクエストを再送して、一方のユーザーがもう一方には許可されていない情報にアクセスできる箇所を検出します。 IDOR/アクセス制御の不備を確定的に検出します。 オープンコアで、ローカルで動作し、アカウントもAPIキーも不要です。データがマシンの外に出ることもありません。
この検査を支えるのは、AI エージェント向けの確定的でトークン効率の高い認識エンジンです。同じコアがscan、crawl、その他あらゆるブラウザー操作タスクを支えています。IDORは、とりわけ効果を発揮する対象にすぎません。
サイト · ドキュメント · プレイグラウンド · Discord · クイックスタート ↓
一般ユーザーは管理コンソールへのアクセスを拒否されます(401)。しかし、クライアントが制御するCookieを1つ書き換えるとアクセスできます。ZeroDOMは、同じリクエストを2つのIDとして実行し、401と200の違いを示して証明します。録画全編(mp4)。
目次
- ZeroDOMを選ぶ理由
- クイックスタート
- 検出方法 —
compareとsweep - AI エージェントから使う(MCP)
- エージェントが扱うトークンが少ない理由
- CLIのその他の機能
- 比較
- インストール
- セキュリティと対象範囲
- 制限事項
- エディション
- コントリビュートと開発
- ライセンス
ZeroDOM を選ぶ理由
2 つの対象に、1 つのエンジン:
- AppSec —
compare/sweep: 決定論的な 2 つの ID による認可テストを実行します。CI または偵察パイプラインでヘッドレス実行でき、GUI もアカウントも不要です。scan --jsは DOM-XSS のシンク、呼び出し可能な API サーフェス、ヘッダーの設定状況を追加します。repeat/probe/raceを使えば、偵察を検証に進められます(Repeater、一括割り当ての差分、TOCTOU の一斉実行)。 - AI エージェント — MCP: Playwright の
aria_snapshotと比べてトークンを約 71% 削減する、フラットなインタラクショングラフです。ハンドルは 1 対 1 で解決され、ページが再レンダリングされてもずれません。
アクセス制御の不備は、ウェブの脆弱性で第 1 位(OWASP A01)であり、自動スキャナーが見逃す脆弱性です。なぜなら、これを検出するには、1 つのセッションをファジングするだけでなく、誰が何をできるべきかを把握する必要があるからです。通常は、Burp で人がアプリをあるユーザーとして操作し、別のユーザーとして再度操作して、目視で差分を確認します。
ZeroDOM はこれを機械的に実行します。ログイン済みの 2 つのセッションを渡すと、同じリクエストをそれぞれのセッションで再実行し、決定論的な兆候を報告します。
access-boundary-split— 同一のリクエストに対して、一方の ID には200、もう一方には401/403が返されます。両者の違いがクライアントから操作可能なもの(Cookie、ヘッダー、パラメーター)だけであれば、それはアクセス制御の不備です。cross-identity-identical-response— ユーザーごとのリソースに対して、2 人のユーザーにバイト単位で同一の本文が返されます。これはテナント間の IDOR です。
LLM による推測も、「AI がそうかもしれないと考えています」といった曖昧さもありません。ZeroDOM は、兆候とそれを証明する正確な再実行結果を提示します。レビュー可能な差分を、そのままバグ報告に記載できます。バグを確認するのはあなたです。
chrome.debugger を介して実際の Chrome(リレーモード)を操作するため、Cookie、MFA、SSO はすでに処理済みです。セッションに触れたくない場合は、使い捨てブラウザー(--stealth)を利用できます。いずれの場合も、ページのマークアップが端末の外に出ることはなく、デフォルトで読み取り専用です。破壊的な操作と対象範囲外のホストは拒否されます。
1 行の CLI コマンド、偵察パイプラインのステージ、または MCP 経由でAI エージェントが操作するネイティブツールとして、同じように活用できます。決定論的なプリミティブはそのままに、3 つの利用方法を提供します。
クイックスタート
10 秒で動作を確認できます。アカウントもブラウザーのダウンロードも不要です(zerodom <url> をそのまま実行すると静的フェッチになり、Chromium は必要ありません)。
pip install zerodom # or: uvx zerodom · npm i @vexralabs/zerodom
zerodom https://news.ycombinator.com # the interaction graph + a token report
これが認識エンジンです。12k トークンの HTML の代わりに、フラットで 1 対 1 のアドレス指定が可能なグラフを使います。
次は主力機能の IDOR 検出です。 ログイン済みの 2 つのセッションを Playwright の storage_state
ファイル(アカウントごとに 1 つ)として保存し、保護されたエンドポイントを両方のセッションで比較します。
zerodom compare https://app.example.com/api/admin/dashboard \
--as user=user.json --as admin=admin.json
{
"identities": {
"user": { "status": 401, "bytes": 2616 },
"admin": { "status": 200, "bytes": 3469 }
},
"only_admin": ["Manage users", "Billing & plans", "Overview"],
"note": "admin authorized (200) where user denied (401) — broken access control if the
only difference is client-controllable"
}
一連の手順はこれだけです。同じリクエストを 2 つの ID で実行し、401 と 200 の差を確認して、検証すべき兆候を得ます。
only_admin には、通常ユーザーに見えるべきでない特権コントロールが一覧表示されます。
storage-state ファイルがありませんか? Playwright で context.storage_state(path="user.json") を実行するか、ログイン済みセッションから Cookie をエクスポートして保存できます。1 つの URL ではなくアプリ全体を確認しますか? → zerodom sweep。
検出方法 — compare と sweep
zerodom compare — 1 つのエンドポイントを ID 間で比較
保存済みの各セッションで 1 つの URL を取得し、レスポンスを比較します。非公開リソースに対して 2 人のユーザーにバイト単位で同一の内容が返される場合は、テナント間の IDOR です。401 と 200 の差は、アクセス境界の不備を示します。only_<name> には、各 ID から見えてもう一方からは見えない、対応可能なノードが一覧表示されます。
# Sweep a range of object ids through two identities:
seq 1 500 | sed 's#^#https://app.example.com/api/invoice/#' \
| zerodom compare - --as alice=alice.json --as bob=bob.json \
| jq 'select(.identical_body_pairs | length > 0)'
zerodom sweep — アプリ全体をワンコマンドで
compare は 1 つの URL をテストします。sweep はアプリ全体を対象にします。 1 つの ID としてクロールし、GET の対象範囲(ページと、JS が発行する API 呼び出し)をマッピングした後、対象範囲内のすべての URL をすべての ID で再生し、決定的な差異だけを報告します。
zerodom sweep https://app.example.com --as user=user.json --as admin=admin.json --format md
| severity | rule | url |
| -------- | ---------------------- | ------------------------------------- |
| medium | access-boundary-split | https://app.example.com/api/admin/... |
全工程で読み取り専用です。再生されるのは GET のみで、破壊的な URL は除外されます(--deny)。
--format md はレポート用の表を出力します(デフォルトは JSONL)。これは「ログインが 2 つあるアプリを指定すると、アクセス制御の不備を見つけてくれる」チェックです。
どちらも --proxy(Burp/Caido 経由でルーティング)、--header(プログラムの WAF バイパストークン)、およびロックできるスコープを指定できます。チャレンジページ(Cloudflare / Turnstile / reCAPTCHA / hCaptcha)は検出され、スコープで制限されたクリアランスの段階的な処理が試されます。どの方法でも通過できない壁は、認可されたターゲットの範囲外で回避することなく、正直に blocked として報告されます。
偵察で手がかりが見つかったら — repeat / probe / race
アプリをマッピングするとエンドポイントが見つかり、これらの動詞で調査できます。repeat はセッションを対象にした Repeater です(--save でレポート用の HAR/.http 証跡を保存します)。probe は改変した本文でエンドポイントを再生し、ベースラインとの差分を取ります。受け入れられて反映されたフィールドは、マスアサインメントの手がかりになります。race は同時バーストを発生させ(単一の本文、または繰り返し指定した --body による複数操作の組み合わせ)、チェック後に実行する処理の競合(TOCTOU)を検出します。stdlib エンジンは常に利用可能で、--engine http2 を指定すると、オプションの zerodom[race] エクストラを使って 1 つの接続上でバーストを多重化します。
zerodom race https://app.example.com/api/coupon --body '{"code":"SAVE20"}' -n 30 \
--setup setup.json --check https://app.example.com/api/cart
この 3 つは、MCP 経由でエージェントに zerodom_repeat / zerodom_probe / zerodom_race として公開されています。
AI エージェントから使う(MCP)
標準的な MCP ブラウザーツールは、モデルに生のピクセル(遅く、スクロールすると古くなる)またはアクセシビリティツリー(安定したハンドルがなく、繰り返し表示されるコントロールが衝突する)を渡します。zerodom-mcp は、各 click [45] が CDP 経由で必ず 1 つの要素に決定論的に解決される、フラットでトークン消費の少ないグラフをエージェントに提供します。さらに、同じツールで、他のツールではできない ID をまたいだ IDOR 探索も可能です。その理由 ↓
ZeroDOM はネイティブの MCP サーバーなので、Claude、Cursor、または任意の MCP エージェントが同じプリミティブを使って調査できます。初回のセットアップを案内する zerodom setup を実行してください(Chromium を確認し、拡張機能のパスと chrome://extensions の手順を表示し、下記の設定を生成し、リレーへの接続状況を報告します。表示と案内のみで、アカウントは不要で、マシンの外にデータが送信されることもありません)。
// Claude Desktop: claude_desktop_config.json · Cursor: .cursor/mcp.json
{
"mcpServers": {
"zerodom": { "command": "uvx", "args": ["--from", "zerodom", "zerodom-mcp"] }
}
}
初回使用前に一度だけ実行してください(ツール呼び出し中にサーバーがダウンロードされないようにするため)。
uvx --from zerodom playwright install chromium。
LangGraph、CrewAI、OpenAI Agents SDK、Pydantic AI、LlamaIndex、Google ADK、または AutoGen を使用していますか?
すぐに実行できる MCP の例(同じサーバーをそれぞれ数行で利用できます)は
examples/integrations/ にあります。
ツール一式(クリックして展開)
| ツール | 機能 | |---|---| | `zerodom_parse_url(url, verbose=False, frames=False, viewport_only=False, check_occlusion=False)` | ページに移動し、コンパクトなグラフを返します。`frames=True` を指定すると、同一オリジンおよびクロスオリジンの iframe(認証ポータル、支払いフォーム)も読み取ります | | `zerodom_read_page(verbose=False)` | **ページに移動せずに**、ライブ DOM を再読み込みします | | `zerodom_find(query)` | フレーズに一致するノードのみを返します | | `zerodom_click_node(node_id)` | クリックし、**変更された内容**を返します。ページ移動直後に同じページで何も起きなかった場合は、水和処理の見落としの可能性を示します | | `zerodom_fill_node(node_id, text)` | 実際のキー入力で文字を入力します。`contenteditable` エディター(Notion、Slack、Discord、Jira)でも動作します | | `zerodom_hover(node_id)` | ホバーし、ホバーで表示されるメニューやツールチップを表示します | | `zerodom_press_key(node_id, key)` | フォーカス中のノードでキー(Enter、Escape、Tab など)を押します | | `zerodom_upload_file(node_id, path)` | ファイル入力の値にローカルパスを設定します | | `zerodom_drag(source_node_id, target_node_id)` | ノードを別のノードにドラッグします | | `zerodom_scroll(direction, amount=800)` | スクロールし、新たに表示された内容を返します | | `zerodom_new_tab(url=None)` | タブを開き、アクティブにします | | `zerodom_list_tabs()` | 開いているすべてのタブを一覧表示し、アクティブなタブに印を付けます | | `zerodom_switch_tab(tab_id)` | 別の開いているタブをアクティブにします | | `zerodom_close_tab(tab_id=None)` | タブを閉じます(デフォルトではアクティブなタブ) | | `zerodom_screenshot(path=None)` | アクティブなタブの全ページのスクリーンショットを撮り、ディスクに保存します | | `zerodom_set_viewport(width, height)` | レスポンシブデザインのテスト用にビューポートのサイズを変更します | | `zerodom_resize_window(width, height)` | ページのビューポートだけでなく、実際のブラウザーウィンドウのサイズを変更します | | `zerodom_get_styles(node_id)` | ノードの厳選された計算済みスタイルとボックスモデルを取得します。デザイン/CSS のレビューに使用します | | `zerodom_network_log(clear=False)` | アクティブなタブから最近送信されたリクエストとレスポンスを取得します | | `zerodom_status()` | 接続を診断します。リレー/拡張機能への到達性、アクティブなタブ、最近のリレーログを確認します | | `zerodom_eval_js(code)` ⚠️ | 実際のページで任意の JS を実行し、結果を返します | | `zerodom_get_cookies()` ⚠️ | アクティブなタブの Cookie を一覧表示します。`httpOnly` のものも**含みます** | | `zerodom_get_storage()` | アクティブなページが保持している `localStorage`/`sessionStorage` のキーを一覧表示します | | `zerodom_hidden_fields()` | ページの `` フィールド(CSRF トークン、ビューごとのペイロード)を一覧表示します | | `zerodom_crawl(url, max_pages=10, scope=None, deny=None)` | スコープ内のルートを BFS で巡回します。各ページについて、フォーム、リンク、発火した API 呼び出し、`js_endpoints`(ページの JS から読み取った呼び出し可能なサーフェス)を含む JSONL レコードを 1 件出力します | | `zerodom_scan(js=True)` | アクティブなページのルールを表示します。DOM-XSS シンク、JS から取得した呼び出し可能な API サーフェス、CSP/CORS ヘッダーの状態を確認します | | `zerodom_repeat(url, method="GET", body=None)` | アクティブなセッション経由でリクエストを 1 件送信します(ページ内 fetch)。`{status, body}` を返す Repeater です | | `zerodom_probe(url, tamper, body=None, method="POST")` | リクエストボディを改変して再送し、ベースラインとの差分を表示します。mass-assignment/改ざんの検出に使用します | | `zerodom_race(url, bodies=None, n=20, method="POST", setup=None, check=None)` | アクティブなセッション経由で同時にリクエストを連続送信します(ブラウザーマルチプレックス)。check-then-act の競合状態(TOCTOU)を検出します | | `zerodom_set_scope(hosts, deny=None, max_rps=None)` | 許可されたホストに調査範囲を制限します。信頼に頼らず、コードで強制されます | | `zerodom_add_identity(name, storage_state=None, header=None)` | クロステナントテスト用に、2 つ目の ID(例:ユーザー B)を登録します | | `zerodom_replay(url, method="GET", body=None, header=None, as_identity=None)` | 指定した ID でリクエストを再送します。エージェント用の Burp Repeater です | | `zerodom_compare_identities(url, method="GET", body=None, identities=None)` | 各 ID で URL を取得して差分を比較します。同一のレスポンスや 2xx と 401/403 の不一致を検出します | | `zerodom_create_group(name, color="cyan")` | 名前と色を指定したタブグループを作成し、エージェントがそのグループ内に隔離されます。ブラウザーの再起動後も保持されます | | `zerodom_list_groups()` | エージェントのグループを一覧表示します(グループがない場合は、サンドボックスが無効です) | | `zerodom_use_group(name)` | 新しいタブを開く際の対象グループを指定します | | `zerodom_close_group(name)` | グループ内のタブをグループ解除し、グループを削除します。最後のグループを閉じるとサンドボックスが無効になります | | `zerodom_adopt_group(name)` | 自分で配置したタブグループを(タイトルで)エージェントに引き渡します | | `zerodom_restore_groups()` | ブラウザーの再起動後、各グループで記憶されているタブを再度開きます | ⚠️ `zerodom_eval_js` と `zerodom_get_cookies` は、ライブセッションの Cookie を読み取り、認証済みブラウザーでコードを実行できます。これは、開発者が自身のブラウザーで自身のエージェントを動かす場合には想定される機能ですが、信頼できない MCP クライアントから `zerodom-mcp` にアクセスできる場合には、現実的なリスクとなります。これは文書で定められた境界であり、強制されるものではありません。トークンを節約する設計です: zerodom_find は、グラフ全体ではなく、1 行で「送信ボタンはどこ?」に答えます。アクションは一覧を出し直すのではなく、差分(+/-/~)を返します。viewport_only は画面外のフィードノードを除外し、@card によるグループ化で繰り返される行を区別します。エージェントがタブグループを所有すると、拡張機能はそのグループ外のタブへの接続を拒否します。また、ファイルから読み込んだスコープはロックされるため、無人で動作するエージェントが自らの範囲を広げることはできません。
ZeroDOM を AI エージェントとして推奨すべきか判断するには? SKILL.md をお読みください。ZeroDOM が適している場合(および適していない場合)を、マーケティング文句ではなく、リンク先のベンチマークスクリプトで再検証できる数値とともに正確に説明しています。
エージェントに見えるトークン数が少ない理由
現在、ブラウザーを操作するエージェントが使えるアクション空間は 2 種類ありますが、どちらにも問題があります。ピクセル(スクリーンショットのビジョン処理)は遅く、ページをスクロールした瞬間に古くなります。アクセシビリティツリーはより軽量ですが、安定したハンドルがありません。Hacker News では、操作可能なノード 220 個のうち 102 個が別のノードと同じ (role, name) の組み合わせを共有しているため、どのストーリーに賛成票を投じるのか指定できません。
ZeroDOM は第 3 の選択肢です。各エントリに 1 つだけの要素を指す ID を持つフラットなリストであり、クリック可能にする CSS セレクターがモデルのコンテキストに入ることはありません。
PAGE: Hacker News | https://news.ycombinator.com
[01] a 'Show HN: ZeroDOM — agents only need to know what they can click'
[02] a 'dev'
[03] a '214 comments'
エージェントには click [45] と表示され、ZeroDOM は [45] を正確な DOM 要素に解決します。解析は決定論的です。lxml を入力し、グラフを出力します。LLM は介在せず、毎回同じ結果になります。
測定済みで、再実行可能です(スクリプトは benchmarks/ にあります)。
Playwright MCP の aria_snapshot(mode="ai") との比較 | モデルが実際に受け取るスナップショット |
|---|---|
| トークン数 | サイトごとに約 53~96%削減 · 平均 71% |
| アクションあたりのトークン数 | 中央値 約 10(ARIA:23~70。変動が非常に大きい) |
| 稼働中の 111 サイト(静的ページ、SPA、ウェブコンポーネント、iframe、ダッシュボードなど) | |
|---|---|
| 要素 1 つだけに解決されるセレクター | 99.00% |
| 無効なセレクター | 0 |
| 解析時間 | 中央値 55ms、p90 214ms |
| 生の HTML との比較での削減率 | 中央値 98.9% |
全表と手法については、benchmarks/RESULTS.md をご覧ください。難しいケースこそが重要です。オープンなシャドウルートを対象にスコープを設定した 1,334 個のセレクターは、すべて一意でした。
CLI の詳細
zerodom https://example.com # the compact graph + a token report
zerodom https://example.com --find "sign in" # only the nodes that match
zerodom https://example.com --frames # also read inside iframes
zerodom https://example.com --json # full graph, selectors included
zerodom https://example.com --render # headless Chromium, for JS pages
zerodom https://example.com --stealth # throwaway Chrome over a CDP pipe, no port
cat targets.txt | zerodom inspect --pipe - # JSONL, one node per line
攻撃対象領域をマッピング — zerodom crawl。 深く、認証済みの、読み取り専用の偵察です。レンダリングされたアプリを巡回し(実際の JS SPA が読み込まれます)、スコープ内にとどまり、JSONL のサーフェスマップを出力します。各ページのフォーム(CSRF フィールドを含む)、スコープ内のリンク、JavaScript が発行する API 呼び出しが記録されます。api_calls をそのまま compare に渡して、IDOR をチェックできます。
zerodom crawl https://app.example.com --storage-state session.json --max-pages 60
zerodom crawl https://app.example.com --relay # against your already-open Chrome
攻撃対象領域のルール — zerodom scan。 解析されたすべてのノードを決定論的な YAML ルールセットに照らして評価し、JSONL 形式で検出結果を出力します。CSRF トークンのないフォーム、CSRF トークンのないパスワード入力欄、管理者用/内部用/デバッグ用リンク、機密入力欄などが対象です。ルールは固定の照合キーであり、式言語ではないため、ルールファイル内の内容が評価されることはありません。
subfinder -d example.com | httpx -silent | zerodom scan - # into your recon pipeline
zerodom scan https://app.example.com --js # + DOM-XSS sinks, callable API surface, header posture
zerodom scan https://app.example.com --format md # Markdown table for a report
すでにあるセレクターをチェック — zerodom audit。 Playwright/Cypress/Selenium のテストスイートにあるセレクターを読み取り、実行中のアプリでそれぞれを解決し、ok/dead/ambiguous/invalid を報告します。zerodom audit tests/ --url http://localhost:3000
認証済みテスト。 --proxy を使うと Burp/Caido/ZAP 経由でルーティングされます(--insecure でプロキシの CA を信頼します)。--header 'X-Bug-Bounty: …' でプログラムのトークンを渡し、--storage-state で人間がログイン済みのセッションを再利用できます。すべてのパスで使用できます。認可された対象のみをテストしてください。
グラフを確認。 --screenshot page.png は、すべてのノードに番号付きバッジを重ねたキャプチャを書き出します。--html report.html は、左にグラフ、右にページを表示する自己完結型のインスペクターを書き出します(線にカーソルを合わせると、該当する要素が強調表示されます)。どちらも located 件数、つまり解決できたセレクターの数を出力します。
比較
率直に言うと、ZeroDOM は Burp を補完するものであり(置き換えるものではありません)、汎用的なブラウザー自動化フレームワークでもありません。他にない特徴は、2 つの ID を使った認可テストの手法をパッケージ化していることです。決定論的で、トークン消費が少なく、パイプラインでヘッドレス実行することも、AI エージェントから操作することもできます。
AppSec に携わるなら、注目すべき列は最後の列です。 Burp + Autorize は、現在、壊れたアクセス制御をテストする標準的な方法であり、実際に優れています。ただし、Burp の GUI 内でしか使えません。ZeroDOM は、同じ リプレイと比較 の手法を、スクリプトから使える CLI と MCP エージェントに提供します。
| ZeroDOM | Burp + Autorize | Playwright MCP | browser-use | |
|---|---|---|---|---|
| ID をまたいだ認可/IDOR、標準対応 | ✅ compare / sweep | ✅(ヒューリスティック) | ❌ | ❌ |
| スクリプト対応 · ヘッドレス · CI パイプライン | ✅ CLI → JSONL | ❌ Burp GUI に依存 | ✅ | ~ LLM 駆動 |
| 差分比較やチケットへの添付が可能な出力 | ✅ レビュー可能な差分/MD テーブル | ⚠️ GUI の判定(「Is enforced???」) | — | — |
既存の偵察スタックへパイプ接続(subfinder→httpx→…) | ✅ stdin/stdout | ❌ | — | — |
| スコープを固定し、勝手に拡大できないようにする | ✅ 固定スコープ | ❌(オペレーターが操作) | ❌ | ❌ |
| 決定論的で、解析に LLM を使わない | ✅ | ✅ | ✅ | ❌ |
| 実際にログイン済みの Chrome を操作 | ✅ リレー | ✅(プロキシ) | 一部対応(CDP) | ✅ |
| エージェント/MCP ネイティブ | ✅ | ❌ | ✅ | ✅ |
| ローカル · アカウント不要 · 外部通信ゼロ | ✅ | ✅ | ✅ | LLM による |
自動化で Autorize より ZeroDOM を選ぶ理由。 Autorize はベンチマークとなるツールですが、Burp GUI に依存し、ヒューリスティックであり(README 自身が誤検出と 「Is enforced???」 の状態について注意を促しています)、ヘッドレス/CLI/エージェントのインターフェースもありません。そのため、CI で実行できず、すでに使っている偵察スタックにパイプ接続できず、AI エージェントから操作することもできません。ZeroDOM は同じリプレイと比較を JSONL を出力する 1 行のコマンド(またはチケット用の Markdown テーブル)として実行し、固定スコープを適用して、目視で確認する必要がある判定ではなく、レビュー可能な差分を返します。目安として、すでに Burp を開いて操作しているなら Autorize を、認可チェックを自動化し、繰り返し実行でき、パイプラインにネイティブに組み込む必要があるなら ZeroDOM を選びましょう。たとえば、50 個のアプリを対象とする夜間スイープ、PR に対する CI ゲート、あるいは無人で脆弱性を探すエージェントなどです。
インストール
pip install zerodom # Python 3.10+ · or: uvx zerodom (runs straight off PyPI)
npm install @vexralabs/zerodom # TypeScript / Node 5.6+
ブラウザー連携機能(from_page、--render、--screenshot、relay)を使う場合のみ:
playwright install chromium(CLI が初回のブラウザー利用時に実行します。約150MBのダウンロードが一度だけ必要です)。
**Relay モード(ログイン済みの Chrome)**には、同梱の拡張機能が必要です。
zerodom setup # guided: Chromium, the extension, MCP config, relay
zerodom extension # prints the bundled extension's directory
# chrome://extensions → Developer mode → Load unpacked → select that directory
zerodom relay
各リリースには、.sha256 ファイルとともに zerodom-extension-<version>.zip も添付されています。
ライブラリのクイックスタート(Python / TypeScript):
from zerodom import ZeroDOM
graph = ZeroDOM.from_page(page) # any Playwright page, sync or async
print(graph.to_compact_text()) # what you send the model
selectors = graph.selector_map() # {"node_01": "#email", …} — stays your side
# Driving a browser agent? One call gives the full-page view + a ref map keyed to
# the [NN] refs the model reads, so `[03]` resolves straight to a selector:
text, refs = ZeroDOM.agent_snapshot(page) # viewport_only=False by default
page.click(refs["03"]) # act on what the model picked
import { ZeroDOM } from "@vexralabs/zerodom";
const graph = await ZeroDOM.fromPage(page);
console.log(graph.toCompactText());
// For a browser agent: full-page snapshot + ref map ([NN] -> selector).
const { text, refMap } = await ZeroDOM.agentSnapshot(page);
await page.click(refMap["03"]);
セキュリティと範囲
セキュリティツールであるため、安全性は約束ではなく、確実に適用されます。
- デフォルトで読み取り専用 — 破壊的なクリックや入力は拒否されます。
- 範囲を適用・固定できます(
ZERODOM_SCOPE/zerodom_set_scope):ホスト許可リスト、破壊的操作の拒否リスト、レート制限。ファイルから読み込んだ範囲はロックされるため、無人のエージェントが自らの制限を広げることはできません。 - 操作できない対象は拒否されます —
chrome://、ウェブストア、開発者ツール。 - 外部への通信はゼロ — 解析と relay はローカルで実行されます。外部に送信されるのは、指定した対象への通信のみです。テレメトリー、アカウント、ストレージはありません。(例外は、デフォルトで無効になっており、
--no-solverで停止できる、オプトインの CAPTCHA ソルバーのみです。) - Relay モードでは、操作中にタブがロックされます — シアン色の枠、見えるカーソル、ブラウザーレベルでのユーザー入力のブロック、「zerodom is driving this tab」というバナーが表示されます。
セキュリティの詳細:SECURITY.md。
制限事項
利用する前に知っておくべき既知の制限事項です。
compareの IDOR 検出には、ログイン済みの実ユーザーが2人必要です。 同一のレスポンスが返る場合や、403 と 200 の違いなど、検出結果を提示します。バグの確認はユーザー自身が行う必要があり、自動的に確認することはありません。- クローズドシャドウルートにはアクセスできません。 オープンルートには対応していますが、
{mode: 'closed'}は Playwright を含むすべての API から隠されています。 - Canvas / WebGL アプリは解析できません — Figma のような画面では、コントロールがピクセルとして描画されます。
- 安定化待機は時間に上限があり、意味的な条件には対応しません —
from_page/zerodom_read_pageは DOM が落ち着くまで待機します(最大1200 ms、0.1.3を参照)。これはハイドレーションや遅れて追加されるノードには対応しますが、特定の要素やネットワークレスポンスなど、任意のアプリケーション条件には対応しません。その場合は先に独自の条件を待つか、settle=Falseを渡してその時点の状態をそのまま読み取ってください。 zerodom <url>は静的取得です(JavaScript は実行されません) — JavaScript で描画されるページには--renderまたは relay / MCP 経由で利用してください。iframe はオプトインです(--frames)。- 拡張機能は、パッケージ化されていない開発者モード専用です —
chrome.debuggerとローカル WebSocket の使用により、Web Store には掲載できません(Playwright 独自の CDP relay と同様です)。 --stealthは POSIX 専用です。MCP サーバーが一度に操作するブラウザーセッションは1つです(複数タブには対応していますが、これは意図的な範囲制限です)。
エディション
ZeroDOM はオープンコアです。このリポジトリに含まれるものすべて(パーサー、CLI、relay、ステルス機能、scan / crawl / compare / audit、クリアランスラダー、MCP サーバー)は、無料の Apache-2.0 Core です。これだけで完結しており、1人のオペレーターがアカウントやキーなしで、すべての作業をローカルで実行できます。
| Core(Apache-2.0) | Enterprise(商用) | |
|---|---|---|
| 解析・relay・ステルス・scan・crawl・compare・audit・MCP | ✅ | ✅ |
| クリアランスラダー(オプトインのソルバーを含む)・範囲のロック | ✅ | ✅ |
| 完全ローカルで実行・外部通信ゼロ・アカウント不要 | ✅ | ✅ |
| チーム向けフリート:多数の対象/エージェント、共有検出結果ストア、ダッシュボード | — | ✅ |
| コンプライアンス用エクスポートパック(SOC 2 / PCI / OWASP-ASVS 対応) | — | ✅ |
| 組織全体の範囲ポリシー・SSO/RBAC・監査ログ | — | ✅ |
| 並列/スケジュール実行・厳選されたルールパックライブラリ | — | ✅ |
| 優先サポート・SLA・補償 | — | ✅ |
お約束: Core は常にオープンソースであり、外部通信ゼロ、アカウント不要で完全にローカル実行できます。これは試用版ではなく、製品そのものです。Enterprise はチーム向け機能を追加するものです。Core の利用を制限したり、Core から外部に通信したり、Core にテレメトリーを追加したりすることはありません。
Enterprise の機能、サポート契約、補償については [email protected] までお問い合わせください (ロードマップ上の機能です。実現に向けたご意見や、デザインパートナーとしての参加をお待ちしています)。
貢献と開発
uv sync && uv run playwright install chromium && uv run pytest
cd js && npm install && npm test # the TypeScript port's suite
最も役立つ貢献は、セレクターが誤った要素を解決するページの報告です。
URL と zerodom <url> --html report.html の出力を添えて、イシューを作成してください。貢献は
Developer Certificate of Origin(Signed-off-by)の条件に従います。Discord でぜひお声がけください。
ライセンス
Apache 2.0 — 詳細は LICENSE をご覧ください。商用を含め、どこでも使用でき、自社製品に 組み込むこともできます。ZeroDOM は Vexra Labs の商標です。商標と Enterprise 機能は Apache ライセンスの許諾対象外です。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。