IPv6ドメイン許可リストの書き方 — Claude Codeサンドボックス
サンドボックスのallowedDomainsとinjectHostsは、IPv6アドレスの書式が別々です。ブラケット表記の書き方と、あいまいな表記をclaude doctorで見つける手順をまとめました。
Claude Codeのサンドボックスは、network.allowedDomainsに書いた宛先へ確認なしで通信を許可し、network.deniedDomainsに書いた宛先は常に遮断します。IPv6アドレスをこれらのリストに書くには、ブラケットで囲む専用の書式が必要です。書式があいまいでも、Claude Codeは設定を読み込んだまま安全側に倒して適用し、claude doctorの警告で知らせるだけです。許可リスト外を一律拒否にするnetwork.strictAllowlistと組み合わせている環境では、この食い違いが「接続できない」という症状になって表に出ます。
IPv6の宛先に届かないとき、まず疑う書き方
IPv6アドレスは:を含むため、そのまま書くとポート番号との境界があいまいになります。example.com:443ならコロンの前後がホスト名とポートだと分かります。::1:443は「::1のポート443」とも「::1:443という1つのIPv6アドレス」とも読めてしまいます。
そこでサンドボックスのドメインリスト(allowedDomains、deniedDomains、WebFetch(domain:...)ルール)では、IPv6アドレスをブラケットで囲みます。"[::1]"はそのアドレスへの全ポートに、"[::1]:443"はポート443だけに一致します。ブラケット表記はClaude Code v2.1.229以降が必要です。
{
"sandbox": {
"enabled": true,
"network": {
"allowedDomains": ["[2001:db8::1]", "[::1]:443", "registry.npmjs.org"]
}
}
}v2.1.229のchangelogには、IPv6に関する1行の変更があります。ドメインリストのIPv6リテラルをブラケット表記にし、あいまいな表記はfail-closed(安全側に倒す)で適用して/doctorで警告する、という趣旨です。ブラケット表記・あいまいな表記の扱い・claude doctorの警告は、すべてこのバージョンで一緒に入った一組の変更です。
allowedDomainsとinjectHostsでは書式が逆になる
見落としやすいのは、IPv6の書式がリストごとに別々だという点です。認証情報をmode: "mask"で保護する設定にはinjectHostsという別のリストがあり、実値を送ってよい宛先を列挙します。同じアドレスでも、2つのリストでは書き方が違います。
同じIPv6アドレスの書き分け
allowedDomains / deniedDomains
"[::1]"のようにブラケットで囲みます。WebFetch(domain:...)ルールも同じ書式です。ポートを絞るなら"[::1]:443"と書きます。
injectHosts
"::1"や"2001:db8::1"のように、正準な圧縮形のまま書きます。プロキシは接続先の生のアドレスだけを照合し、ポートは見ません。
injectHostsは、ブラケット付きの表記、ゾーンID付きの表記、圧縮の仕方が違う表記のどれとも一致しません。allowedDomainsのブラケット表記をそのままコピーすると、一致しないエントリができあがります。
認証情報は注入されず、プロキシにはサンドボックス内で見えるのと同じ代替値のまま素通りします。この状態はclaude doctorが警告で知らせてくれます。文面は「Sandbox credential injectHosts entries can never match their destination」です。この検査もv2.1.229以降が対象です。
もう1つ押さえたいのが、injectHostsのホストはallowedDomainsからも到達できる必要がある点です。プロキシが認証情報を差し込むのは、ドメイン許可リストが通した接続だけだからです。IPv6の宛先にmaskを使うなら、allowedDomainsにはブラケット表記、injectHostsにはブラケットなしと、同じアドレスを2回書き分けることになります。maskの設定そのものはClaude Codeの認証情報マスキングの記事で扱っています。
あいまいな表記はdenyとallowで結果が逆向きに倒れる
::1:443のようにブラケットで囲まずに書いたIPv6のエントリは、複数の読み方ができます。Claude Codeはどれか1つを推測せず、リストの性質に応じて安全側へ倒します。
`::1:8080`と書いたときの扱い
denyリスト
エントリが解釈できるすべての読み方を拒否します。「::1のポート8080」と「::1:8080というアドレス」の両方が止まります。解釈できる読み方が1つもないエントリは、何もブロックしません。
allowリスト
書いた範囲より広くは許可しません。ホストとポートの読み方としてきれいに解釈できるなら、その読み方へ書き換えて許可します。書き換えもできなければ、エントリを許可リストから落とすことがあります。
denyは「疑わしきは拒否」、allowは「疑わしきは許可しない」という、逆向きの安全側設計です。
落ちたエントリは宛先に届かないだけなので、症状としては単なる接続失敗に見えます。調べる入口がclaude doctorです。
症状から切り分ける手順
IPv6の宛先に届かないとき、設定ファイルを読み返す前に次の順で確認すると、書式の問題かどうかを早く切り分けられます。
IPv6の宛先に届かないときの確認順
- 1
claude doctorを実行する
プロジェクトのディレクトリでターミナルから
claude doctorを実行します。「Sandbox network domain entries have unreliable spellings」の警告が出ていないかを見ます。 - 2
該当エントリをブラケットで書き直す
警告が出たエントリを
"[::1]:8080"のようにブラケット表記へ直します。ポートを付けないなら"[::1]"です。 - 3
認証情報マスキングを使っていればinjectHostsを見る
injectHostsに同じアドレスを書いているなら、ブラケットなしの正準圧縮形になっているかを確認します。こちらは「can never match」の警告が手がかりです。 - 4
リストの種類を見直す
denyに書いた表記が両方の読み方を止めていないか、allowに書いた表記が落とされていないかを、2つのリストを見比べて確かめます。
実機で確認できる範囲
claude doctorの位置づけは、v2.1.287でclaude doctor --helpを実行すると次のように表示されます。
claude doctor --helpUsage: claude doctor [options]
Check the health of your Claude Code installation. Reads settings files in the
current directory without a trust prompt. For a full checkup that can also fix
issues, run /doctor in a session.
Options:
-h, --help Display help for commandここから読み取れる点が2つあります。1つは、カレントディレクトリの設定ファイルを信頼確認なしで読むことです。許可リストを書いたプロジェクトのディレクトリで実行すれば、そのリポジトリの.claude/settings.jsonが診断の対象に入ります。もう1つは、修復まで求めるときは、セッション内の/doctorを使うことです。ターミナルのclaude doctorは診断の表示が目的で、デバッグ手順の公式ページも「セッションを始めずに読み取り専用の診断を出す」と説明しています。
実際の警告文は設定の中身次第で変わるため、ここでは載せていません。警告の見出しは、前の節で挙げた2つの文言です。
ホスト名が拒否されるとき、IPアドレスで許可する場合
IPv6アドレスをリストに書く場面は、ホスト名がそもそも通らない場合に限りません。サンドボックスのプロキシは、許可リストを通ったホスト名を解決した後、ローカルアドレスにしか解決されない名前を拒否します。ここでいうローカルアドレスには次のものが含まれます。
127.0.0.1のようなループバックアドレス- クラウドのメタデータ用エンドポイント
169.254.169.254のようなリンクローカルアドレス - 自分のマシンに割り当てられたアドレス
localhostと*.localhostだけは、ループバックへの解決が許されています。社内のホスト名が10.0.0.0/8のようなプライベート範囲に解決される場合は、そのまま接続できます。拒否される解決先へ接続したいときは、そのIPアドレスをallowedDomainsに足します。
この拒否はv2.1.284以降の挙動で、それより前のプロキシは解決先へそのまま接続していました。拒否されたコマンドには403が返り、本文に「Connection to myapp.test blocked: resolved to a loopback address」のような理由が付きます。127.0.0.1を指す開発用のホスト名なら、["myapp.test:3000", "127.0.0.1:3000"]のように、ホスト名と解決先のIPをポート付きで並べます。名前が::1に解決される場合は、IPの側を"[::1]:3000"とブラケット表記にする形になると考えられます。ポートを付けないIPのエントリは、そのアドレスで待ち受ける全サービスを開けます。
この拒否の確認は、ホスト名に対してだけ働きます。IPアドレスへの接続は、許可ドメインと権限モードが決めます。上流の社内プロキシ経由で出す接続も、名前解決をそのプロキシが行うので、この確認は行いません。
承認プロンプトとauto modeでの扱いの違い
許可リストに書いていない宛先へ接続したときの動きは、権限モードで変わります。
| 権限モード | 許可リスト外への接続 |
|---|---|
bypassPermissions | 許可リスト外への接続プロンプトなしで許可 |
通常のモード・acceptEdits・plan mode | 許可リスト外への接続承認プロンプトが出る |
| auto mode | 許可リスト外への接続コマンドが宛先を名指しして分類器が承認したときだけ許可 |
dontAsk | 許可リスト外への接続拒否 |
承認プロンプトで「はい、今後は聞かない」を選ぶと、宛先がWebFetch(domain:...)の許可ルールとしてローカル設定に保存されます。以後のセッションでも許可が続きます。
auto modeでは、通常プロンプトは出ません。Bash・PowerShell・Monitorのコマンドが、必要なホストを:ポート付きのIPアドレスも含めて自分で名指しし、分類器がコマンドと一緒に審査します。承認された宛先は、そのコマンドが動いている間だけ開きます。設定には何も書き足されません。ただし、askルールでそのコマンドに確認が必須になっている場合は、ダイアログにホストが並んで表示され、そこで承認すると両方が許可されます。この仕組みはv2.1.271以降が必要です。許可を求められた宛先を後から設定へ書き足す作業は発生しないので、ブラケット表記の出番は、常設で開けておきたい宛先に限られます。
「今後は聞かない」の保存先にも条件があります。サンドボックスが管理者必須の状態だと、ルールはローカル設定でなくユーザー設定へ保存されます。ユーザー設定のルールはすべてのプロジェクトに効くので、IPv6の宛先が1つのリポジトリの外まで許可される点に気をつけてください。
strictAllowlistは、ユーザー設定・管理設定・CLIの--settingsのいずれかでtrueにしたときだけ効きます。許可リスト外の宛先は、権限モードに関係なくプロキシが拒否します。bypassPermissionsでも同じです。この状態では承認プロンプトが出ないので、IPv6アドレスのブラケット書式が合っていないと、接続失敗が黙って積み上がります。この設定はv2.1.219以降で使えます。効くのはサンドボックス内のコマンドだけで、WebFetchツールは従来どおり権限ルールで判定されます。
注意したいのは、strictAllowlistかallowManagedDomainsOnlyで許可リストを固定していると、コマンドごとの宛先指定は断られる点です。deniedDomainsのエントリも、コマンドごとの指定では開きません。IPv6の宛先を使い続けるなら、ブラケット表記でallowedDomainsへ書いておく必要があります。allowManagedDomainsOnlyが有効な組織では、管理設定のallowedDomainsにしか効かないため、管理者に追加を依頼します。
まとめ
IPv6アドレスは、allowedDomainsとdeniedDomainsではブラケット表記、injectHostsではブラケットなしの圧縮形と書き分けます。迷ったらclaude doctorを実行し、2つの警告が出ないことを確かめます。