Claude Code WebFetch権限ルール — ドメイン単位の許可設計
WebFetchツールのdomain:ルールでドメイン単位の許可・拒否を書く方法と、裸のWebFetchルールとの挙動の違い、サンドボックスのネットワーク許可リストとの関係までまとめています。
Claude CodeのWebFetchツールは、ドメイン単位で許可・拒否を書くWebFetch(domain:...)ルールで細かく制御できます。書き方を誤ると「特定のドメインだけ許可したつもりが全ドメインに広がっていた」「サンドボックス内のcurlには効いていなかった」という食い違いが起きます。原因はほぼ、domain:が付くかどうかと、WebFetchとサンドボックスが別々の許可リストを持つことにあります。
Claude CodeのWebFetch権限ルールでできること
WebFetch権限ルールはsettings.jsonのpermissions.allowまたはpermissions.denyに書く文字列で、対象はリクエスト先のホスト名です。書式は3種類あります。
| 書き方 | 対象 |
|---|---|
WebFetch(domain:example.com) | 対象example.comへの取得のみ |
WebFetch(domain:*.example.com) | 対象example.com配下の全サブドメイン(api.example.comやa.b.example.comも含む。example.com自体は含まない) |
WebFetch(domain:*) | 対象全ドメイン |
マッチングは大文字小文字を区別せず、ルール側・ホスト名側の末尾ドットも同一視します(example.com.とexample.comは同じ扱い)。ワイルドカードが先頭の*.または単独の*以外の位置にあるとき、*はドットとドットの間のテキスト1つ分にしかマッチしません。WebFetch(domain:example.*)はexample.orgにはマッチしますが、example.evil.comにはマッチしません(*がevil.comというドットをまたぐ文字列になってしまうため)。攻撃者が取得しうるドメインへ末尾ワイルドカードが広がらないための制約です。
同じルール文字列は、settings.jsonだけでなくコマンドラインのフラグでも渡せます。v2.1.285でclaude --helpを実行すると、次のように表示されます。
--allowedTools, --allowed-tools <tools...>
Comma or space-separated list of tool names to allow (e.g. "Bash(git *) Edit")
--disallowedTools, --disallowed-tools <tools...>
Comma or space-separated list of tool names to deny (e.g. "Bash(git *) Edit")ヘルプの例はBash(git *)ですが、公式のツールリファレンスは、権限ルールをpermissions.allow・permissions.deny・/permissionsのほかにこの2つのフラグでも指定できると説明しています。(や*はシェルに解釈されるので、--disallowedTools "WebFetch(domain:*.example.com)"のように引用符で囲みます。
裸のWebFetchとWebFetch(domain:*)は同じではない
どちらも「全URLを対象にする」点は同じですが、allowとdenyそれぞれでの挙動が異なります。
全取得に効く2つの書き方
裸の WebFetch
allowではプロンプトなしで取得します。denyではWebFetchツール自体がコンテキストから消え、取得を一切できなくなります。どちらの場合も、サンドボックス化コマンドが到達できるホストは変わりません。設定ファイルを使わずツールだけ止める方法はCLAUDE_CODE_DISABLE_WEB_FETCHにあります。
WebFetch(domain:*)
allowではプロンプトなしで取得し、サンドボックス化コマンドも任意のホストへ到達できます。denyではツールは残ったまま取得のたびに拒否し、サンドボックス化コマンドもどのホストにも到達できなくなります。
違いの本質は、domain:付きのルールだけがサンドボックスの許可・拒否ドメインリストにも反映される点にあります。裸のWebFetchルールはWebFetchツールの挙動だけを変え、Bashで実行するcurlのようなサンドボックス化コマンドの到達可能ホストには影響しません。
もう一つ差が出るのが、claude.aiに公開されたアーティファクトの読み取りです。裸のWebFetchのdenyやaskはこの読み取りに適用されず、WebFetch(domain:claude.ai)やWebFetch(domain:*)のようなdomain:ルールは適用されます。コンテンツ側のホスト*.claudeusercontent.comを対象にしたdomain:ルールと、Artifactルールも同じ扱いです。v2.1.268より前は、裸のdenyがアーティファクトの読み取りまで止めていました。
Claudeに自由に取得させつつサンドボックスの許可リストはそのままにしたい場合は、裸のallow形式を使います。
{
"permissions": {
"allow": ["WebFetch"]
}
}この設定では、Claudeへページ取得を頼むとプロンプトなしで取得します。一方、サンドボックス化されたcurlで許可リスト外のホストへ接続しようとすると、Claude Codeは改めてそのホストの確認を求めます(autoモードでは、コマンドに書かれたホストを分類器が確認します)。裸のルールはホストを許可リストへ追加していないためです。
許可ルールを書いても残るWebFetch独自の制約
許可ルールで通した取得でも、WebFetch自身の挙動は変わりません。運用で引っかかりやすいものを挙げます。
- ドメイン安全チェック: 取得の前に、Anthropicが管理するブロックリストと照合するため、ホスト名(URLやページ内容は含まない)が
api.anthropic.comへ送られます。合格したホスト名は5分間キャッシュされます。ネットワークがapi.anthropic.comを遮断していると、WebFetchは失敗します。設定のskipWebFetchPreflight: trueでこのチェックを外せますが、その場合はブロックリストを参照せずに取得するため、範囲を絞りたければ権限ルールと併用します - ドットのないホスト名は拒否:
localhostや社内のhttp://wiki/のようなホスト名は、リクエストの前にはねられます。エラー文はWebFetch cannot fetch localhost or other hostnames without a dot. To reach a local server, use Bash with curl instead.で、ローカルサーバーへはBashのcurlを使うよう案内されます - リダイレクトは自動では追わない: 別のホストへ転送されるURLでは、元のURLと転送先を示す結果が返り、Claudeが転送先をあらためて取得します。
- 大きなページは切り詰め: 固定の文字数を超えるページは、処理の前に切り詰められます。末尾に載っている情報は、抽出の対象に入らないことがあります
- サーバー側で識別できる: リクエストの
User-AgentはClaude-Userで始まります。取得を許可・識別したいサイト運営側は、この文字列を手がかりにできます - 結果は要約: ページは小さな高速モデルで抽出され、Claudeが受け取るのはその答えです。「ページに書いていない」という結果は、抽出用のプロンプトが聞かなかっただけのこともあります。原文が要るときは
curlが公式の逃げ道です
HTTPのURLはHTTPSへ自動で切り替わり、取得結果は既定で15分キャッシュされます。キャッシュ時間の変更にはv2.1.233以降で使える環境変数CLAUDE_CODE_WEBFETCH_CACHE_TTL_MS、5分の取得期限の変更にはv2.1.268以降のCLAUDE_CODE_WEBFETCH_DEADLINE_MS(0で無期限)を使います。
組み込みの事前承認ドメインは自分のルールとどう共存するか
WebFetchには、権限ルールを何も書いていなくてもプロンプトなしで取得できる、組み込みの事前承認ドキュメントドメイン一覧があります。ManualモードやacceptEditsモードでは、この一覧に載っているドメインと、自分の権限ルールですでに許可・拒否したドメインだけがプロンプトをスキップします。それ以外の未知のドメインは都度確認を求められ、確認プロンプトには3つの選択肢があります。
- Yes: この1回だけ承認する。次に同じドメインへ取得しようとしても再度プロンプトが出る
- Yes, and don't ask again for
<domain>: 承認した上で、そのドメインのWebFetch(domain:...)allowルールをそのリポジトリの.claude/settings.local.jsonに保存する。組織がallowManagedPermissionRulesOnlyを設定している場合、この選択肢自体が表示されなくなる - No, and tell Claude what to do differently: 取得を拒否する
autoモードとbypassPermissionsモードはこのプロンプトを原則スキップしますが、明示的なaskルールがそのドメインに一致する場合は例外としてプロンプトが残ります。逆に、事前承認ドメインであってもdeny ask allowいずれかの明示的なWebFetch(domain:...)ルールを書けば、そちらが優先されます。組み込みの事前承認を上書きして、特定のドキュメントドメインだけ改めて確認させる、あるいは完全にブロックすることもできます。
ドメインを通す仕組みは3つあり、効き先がそれぞれ違います。
ドメインを通す仕組みごとの効き先
組み込みの事前承認一覧
WebFetchだけに効きます。サンドボックス化コマンドは引き継がないので、
curlから同じドメインへ確認なしで届かせたいなら、別に許可を書きます。WebFetch(domain:...)のallow
WebFetchとサンドボックス化コマンドの両方に効きます。
curlまで通したいドメインは、これが最も少ない書き方です。sandbox.network.allowedDomains
サンドボックス化コマンドだけに効きます。WebFetchはこの一覧も組織のネットワーク許可リストも参照しないため、追加してもWebFetch側のプロンプトは止まりません。
サンドボックスのネットワーク許可リストとどう連動するか
Claude Codeのサンドボックスは、filesystem isolationとは独立したネットワーク隔離レイヤーを持ちます。サンドボックス化コマンドがどのホストへ到達できるかは、sandbox.network.allowedDomainsの設定と、WebFetch(domain:...)のallowルールを合わせたリストで決まります。逆に特定のホストを明示的に遮断したい場合はsandbox.network.deniedDomainsにドメインを書きます。allowedDomainsはあくまで許可リストであり、到達を止める役割はdeniedDomains側が担います。
既定ではどのドメインも事前許可されていません。サンドボックス化コマンドが未知のドメインへ接続しようとすると承認を求められ、「Yes」ならそのセッションの間だけ、「Yes, and don't ask again」を選ぶとWebFetch(domain:...)のallowルールとしてローカル設定に保存され、以後のセッションでも許可されたままになります。保存されたルールは/permissionsコマンドの一覧から確認できます。
autoモードでは、承認の代わりにコマンド自身が必要なホストを申告します。registry.npmjs.orgのようなドメインや*.pythonhosted.orgのようなワイルドカード、IPアドレスを、ポート付きでも書けます。分類器がコマンドとホストをまとめて確認する仕組みで、v2.1.271以降で使えます。deniedDomainsは申告があってもブロックのままで、後述のstrictAllowlistやallowManagedDomainsOnlyで許可リストを固定している場合、申告は受け付けられません。
サンドボックスのドメインリストでは、ワイルドカードは先頭の*.と単独の*の2形式のみが有効です。それ以外の位置のワイルドカード(example.*など)はWebFetchツール自体のマッチには使えても、サンドボックス化コマンドの到達可否には影響しません。
組織・チーム運用では2段階の締め方があります。
strictAllowlist: ユーザー設定・管理設定・CLIの--settingsでtrueにすると、許可リスト外のホストへの接続はプロンプトを出さずに拒否されます。リポジトリの.claude/settings.jsonや.claude/settings.local.jsonに書いても効果はありませんallowManagedDomainsOnly: 管理設定でこれを設定すると、許可リスト外のドメインは自動的にブロックされ、管理設定に登録されたallowedDomainsとWebFetch(domain:...)ルールだけが有効になります
どちらもサンドボックス化コマンドにのみ適用され、WebFetchツール自体は権限ルールに従って動きます。IPv6アドレスをドメインリストに書く場合は[::1]のように角括弧で囲む必要があり(ポート指定は[::1]:443)、書き方の細かい注意点はIPv6ドメイン許可リストの書き方 — Claude Codeサンドボックスにまとめています。
機能ごとに入ったバージョン
WebFetchとサンドボックスのドメイン指定は、次のバージョンで広がってきました。古い環境で書式が効かないときの手がかりになります。
ドメイン指定まわりの追加
- v2.1.172WebFetchのワイルドカード
WebFetch(domain:*.example.com)などのワイルドカードが、取得のマッチに使えるようになりました。 - v2.1.186単独の * をサンドボックスが認識
サンドボックスのドメインリストで、
WebFetch(domain:*)の単独*が有効になりました。 - v2.1.219strictAllowlist
許可リスト外のホストを、プロンプトなしで拒否できるようになりました。
- v2.1.229IPv6の角括弧表記
[::1]や[::1]:443の書き方が使えるようになりました。それ以前は、::1:443の末尾を機械的にポート番号と読んでいました。 - v2.1.233 / v2.1.268キャッシュと期限を環境変数で調整
v2.1.233でキャッシュ時間、v2.1.268で取得期限を変える環境変数が入りました。
- v2.1.271autoモードのコマンド単位の許可ホスト
コマンドが必要なホストを自分で申告する方式が入りました。
WebFetchの許可設計を使い分ける
用途別にどの書き方が向くかをまとめます。
| 用途 | おすすめの書き方 | 理由 |
|---|---|---|
| 特定の社内ドキュメントサイトだけ許可 | おすすめの書き方WebFetch(domain:docs.example.com) | 理由到達範囲を1ホストに固定できる |
| 自社ドメイン配下のサブドメインを丸ごと許可 | おすすめの書き方WebFetch(domain:*.example.com) | 理由ルートexample.comは含まれないため、外部公開ページと社内サブドメインを分けやすい |
| Claudeに自由に調査させたいが、サンドボックス側の許可は絞ったまま維持したい | おすすめの書き方裸のWebFetchをallow | 理由ツール取得は自由にしつつ、Bash経由の到達範囲は既存の許可リストで縛れる |
| チーム全体でリスクの高いドメインを遮断 | おすすめの書き方WebFetch(domain:evil.example)をdeny | 理由危険なホストだけ確実に止める |
| 組織全体でホワイトリスト運用を徹底 | おすすめの書き方管理設定のallowManagedDomainsOnly + strictAllowlist | 理由プロンプトへの依存をなくし、許可リスト外は自動拒否にする |
ルールの評価順は他の権限ルールと同じく、deny → ask → allowの順で最初に一致したものが採用されます。範囲の広いdenyルールは、範囲の狭いallowルールがあっても優先されるため、WebFetch(domain:*)をdenyに置くと個別のallowルールごと遮断されることに注意してください。ユーザー設定でallowしてもプロジェクト設定のdenyが勝ち、逆にユーザー設定のdenyがプロジェクト設定のallowに勝つのも同じ理由です。PreToolUseフックがallowを返しても、一致するdenyやaskのルールは効きます。
よくあるつまずき
- 裸の
WebFetchをdenyしたのにBashのcurlは通ってしまう: 裸のdenyルールはWebFetchツールを消すだけで、サンドボックス化コマンドの到達範囲は変えません。curl側も止めたいならsandbox.network.deniedDomainsに対象ホストを書くか、strictAllowlistを有効にして許可リスト外を丸ごと拒否します。Bashのdenyルールでcurlを止める方法もありますが、別のパス指定やsh -cの中の同じプログラムには一致しないので、サンドボックスの許可リストと組み合わせる前提になります WebFetch(domain:example.*)が思ったドメインにマッチしない: 末尾以外の位置のワイルドカードは、ドットとドットの間の1区画にしか一致しません。サブドメインをまとめて許可したいなら先頭に*.を置く形に書き換えます- リポジトリの
.claude/settings.local.jsonにstrictAllowlistを書いても効かない: この設定はユーザー設定・管理設定・CLIの--settingsでのみ有効です。リポジトリスコープの設定ファイルに書いても無視されます - IPv6アドレスを許可リストに書いたのにマッチしない: 角括弧なしの
::1:443はアドレスとポートの両方の読み方ができてしまう曖昧な表記です。claude doctorを実行するとSandbox network domain entries have unreliable spellingsという警告で該当エントリーを教えてくれるので、[::1]:443の形に書き直します localhost:3000の開発サーバーをWebFetchで読ませようとして失敗する: 権限ルールの問題ではなく、ドットのないホスト名を拒否するWebFetchの仕様です。ルールを足しても通らないので、Bashのcurlで取得させます- 許可リストに入れたのにWebFetchが止まる:
api.anthropic.comへのドメイン安全チェックが通っていない可能性があります。社内ネットワークで遮断している場合は、そのドメインを許可するかskipWebFetchPreflightを検討します
まとめ
判断の分かれ目は2つです。domain:を付けるかどうかで、ルールがWebFetchだけに効くのかサンドボックスの到達範囲まで変えるのかが決まります。そして事前承認一覧とsandbox.network.allowedDomainsは片側にしか効かないので、両方の経路を通したいドメインはWebFetch(domain:...)のallowで書きます。サンドボックス全体の設計思想はClaude Codeのサンドボックス設計、個人・チーム・企業別の実装値はClaude Codeセキュリティ・権限ガイドで扱っています。