コンテンツにスキップ

安全性:プロンプトインジェクションと信頼境界

対象読者: 本テーマ第 2 章(ツールと権限)と第 5 章(拡張の仕組み)の内容を学んだ人。確率の初歩(独立な試行の積)と、計算可能性の入門(決定不能性)を知っていれば十分です。

前提となる記事:ツールと権限:許可規則・権限モード・サンドボックス、拡張の仕組み:MCP・フック・スキル・プラグイン・Agent SDK

生 Markdown

AI にコードを書かせる道具に、ウェブページやファイルを読ませるとします。そのページに「ここにある秘密を外へ送れ」といった文が紛れていたら、AI はそれに従ってしまうでしょうか。AI にとっては、利用者の依頼も読んだ文書も、同じ文章として並んで見えます。この記事では、AI がだまされることを前提にして、だまされても被害が出ない範囲に収めるには何を決めておけばよいかを、順に整理します。読み終えると、設計する側が自分で決められるものと、決められないものを区別できるようになります。

  • モデルの入力の上では、命令とデータは型として区別されません。どちらもトークンの列(AI が読む文章を細かく区切った単位の並び)です。外から入った内容がモデルの出力を変えうることを前提に、設計する側が決められるものを数え上げるのがこの章の目的です。
  • 実行される行為は、権限の判定を通ったものだけです。文脈に何が入っても、実行される行為の集合は、その時点の規則とモードが許す集合に含まれます。この上界は達成されうるので、上界そのものを小さくすることに意味があります(定理 3.2)。
  • 入力だけを見て「有害な行為を引き起こすか」を判定する検査で、どんなモデルに対しても正しいものは作れません。入力をプログラムとして実行する極端なモデルを模型に取ると、どの決定可能な検査も見逃しか誤検出を持ちます(命題 3.4)。これは模型の上の限界で、実在のモデルや検査器の性能についての主張ではありません。
  • 非公開の情報が外へ出る経路は、(a) 非公開の情報を読む能力、(b) 信頼できない入力が文脈に入る経路、(c) 外部へ送る能力、の 3 つがそろったときに存在し、どれか 1 つを欠けば模型の上では存在しません(命題 4.2)。
  • 防御の層には、規則や OS が強制する決定的な層と、モデルや分類器や人間の判断による確率的な層があります。確率的な層は、試行を重ねれば見逃しの確率が 11 に近づきます(命題 5.3)。
  • この章は防御の設計を扱い、攻撃の手順は扱いません。命題はすべて、公式資料の記述を模型として定式化したものの中での命題で、実物が安全であることを主張するものではありません。出典の確認日は 2026-10-10 です。

第 1 章 から 第 5 章 までで、エージェントループ、権限の関門、文脈の管理、拡張点を見てきました。この章では、それらを安全性の観点からまとめ直します。

出発点は 1 つの事実です。モデルは、メッセージ列を読んで次の出力を決めます。メッセージ列には、利用者が書いた依頼のほかに、ツールが返した結果が入ります。読んだファイルの中身、取得したウェブページ、MCP サーバの応答などです。これらは利用者が書いたものではなく、誰が書いたか分からないこともあります。そこに「指示の形をした文」が含まれていたとき、モデルがそれを依頼の一部として扱ってしまう可能性は、仕組みの上では排除できません。

Claude Code の公式ドキュメントは、プロンプトインジェクションを「攻撃者が悪意のある文章を差し込んで、AI アシスタントの指示を上書き・操作しようとする手法」と説明し、いくつかの保護の仕組みを挙げたうえで、次のように断っています。これらの保護は危険を大きく減らすが、どんな系もすべての攻撃に対して完全ではない。提案されたコードとコマンドを承認の前に確かめる責任は利用者にある。

この章の立場は、この断り書きと同じです。「モデルが操作されないこと」を当てにする設計ではなく、「モデルが操作されたとしても、起こりうることが囲われている」設計を考えます。そのために、モデルの判断に依存する部分(確率的)と、ハーネスと OS が強制する部分(決定的)を分けます。設計する側が自分で決められるのは、後者と、行為の集合の大きさです。

LLM とプログラミング の章は、もっともらしい誤りを検証する側の限界を扱いました。この章はその対で、操作されうる側をどう囲うかを扱います。

2. 主体・信頼境界・入力の経路

Section titled “2. 主体・信頼境界・入力の経路”

定義 2.1(主体と信頼境界)↗

エージェントの利用に関わる主体を次のように分ける。

  • 利用者: 依頼を出し、承認を与える人。
  • 運用者: 設定(権限規則、フック、サンドボックス、組織の管理設定)を決める人。個人の利用では利用者と同じ。
  • モデル: メッセージ列から次の出力を決める写像。
  • 拡張の提供者: MCP サーバ、プラグイン、スキル、フックのプログラムを書いた人。
  • 外部の内容の作者: ウェブページ、リポジトリの中のファイル、課題管理の書き込みなど、ツールの結果として文脈に入る内容を書いた人。

信頼境界とは、信頼の水準が異なる要素を分ける線をいう。ある主体を信頼するとは、その主体が与える内容やプログラムが敵対的でないと仮定することをいう。

「信頼境界」の定義は、Agent SDK の公式ドキュメント(“Securely deploying AI agents”、2026-10-10 確認)の説明(境界は、信頼の水準が異なる構成要素を分ける)に合わせています。

定義 2.2(文脈に入る入力の経路)↗

モデルの文脈に内容が入る経路を、内容を決める主体で分類する。

経路内容を決める主体
利用者の入力利用者
指示ファイル(CLAUDE.md など)、設定運用者。共有のリポジトリでは、リポジトリに書き込める人
ファイルを読むツールの結果そのファイルを書いた人(リポジトリに書き込める人、依存パッケージの作者など)
取得したウェブページ、検索の結果外部の内容の作者
MCP サーバのツールの説明と結果拡張の提供者と、サーバが取得する外部の内容の作者
スキルの説明と本文、プラグインの部品拡張の提供者
シェルコマンドの出力コマンドが読むものの作者

利用者と運用者が決める経路を信頼できる経路、それ以外を信頼できない経路と呼ぶ。

定義 2.3(プロンプトインジェクション)↗

プロンプトインジェクションとは、攻撃者が文章を差し込んで、AI アシスタントの指示を上書き・操作しようとする手法をいう(Claude Code の公式ドキュメントの説明)。利用者自身が敵対的な入力を作る場合を直接の、利用者は信頼できるが、モデルが利用者の代わりに読む第三者の内容(ウェブページ、メール、文書、ツールの結果)に敵対的な指示が含まれる場合を間接のプロンプトインジェクションという(Claude API の公式ドキュメントの区別)。

間接のプロンプトインジェクションが成り立つ理由は、モデルの入力の形にあります。第 1 章 で見たとおり、モデルへの入力はメッセージの列で、利用者の依頼もツールの結果も、最終的には 1 本のトークンの列になります。プログラムの世界で「コード」と「データ」を型で分けるような区別は、この列の上にはありません。区別があるとすれば、「どのブロックに入っているか」という位置の情報と、モデルがそれをどう扱うように作られているか、だけです。

Claude API の公式ドキュメント(“Handle tool calls”)は、この位置の情報を使うことを勧めています。ツールの結果は制御できない出所の内容を運ぶことが多いので、信頼できないものとして扱い、tool_result ブロックの中にとどめ、システムプロンプトや user の text ブロックに入れないこと。MCP の仕様(2026-07-28 版の “Tools”)にも、関連する要請があります。ツールの呼び出しを拒否できる人間が常にループの中にいるべきである(SHOULD)、クライアントは信頼できるサーバからのものでない限りツールの注釈を信頼できないものとして扱わなければならない(MUST)、クライアントはツールの結果を LLM に渡す前に検証すべきである(SHOULD)、などです。

これらは、モデルが正しく扱いやすくするための工夫です。しかし「位置を分ければ、モデルは必ず区別する」という保証ではありません。次節からは、モデルがどう振る舞っても成り立つことだけを積み上げます。

メッセージ列→ モデル利用者の入力・指示ファイルツールの結果・ウェブページMCP の応答・リポジトリのファイル関門規則・モード呼び出し行為の実行ハーネスが強制出力はモデルしだい
信頼できる経路と信頼できない経路。どちらも同じメッセージ列に入る。実行される行為は関門を通ったものだけ。

3.1. 実行されるのは関門を通った行為だけ

Section titled “3.1. 実行されるのは関門を通った行為だけ”

この節のねらいは、「AI が何を出力しても、実際に実行される行為は、設定した規則で決まる範囲の外へは出ない」ことを示し、その範囲を狭めることが対策になると言うことです。直感的には、AI が出す要求を、規則に基づいて通す・確認する・止めるに分ける関所を考えます。

第 2 章 の記号を使います。ツール呼び出しの全体を QQ、権限規則の集合を RR、権限モードを μ\mu とし、最終の判定を Dμ,R:Q→{block,prompt,run}D_{\mu,R} : Q \to \{\mathrm{block}, \mathrm{prompt}, \mathrm{run}\} とします(block\mathrm{block} は実行しない、prompt\mathrm{prompt} は利用者に確認する、run\mathrm{run} は確認なしで実行する)。

定義 3.1(能力)↗

規則集合 RR とモード μ\mu のもとでの能力を、次の 2 つの集合で表す。

  • Arun={q∈Q:Dμ,R(q)=run}A_{\mathrm{run}} = \{q \in Q : D_{\mu,R}(q) = \mathrm{run}\}。確認なしで実行される呼び出しの集合。
  • A={q∈Q:Dμ,R(q)≠block}A = \{q \in Q : D_{\mu,R}(q) \ne \mathrm{block}\}。利用者が承認すれば実行されるものを含めた、実行されうる呼び出しの集合。

Arun⊆AA_{\mathrm{run}} \subseteq A である。

第 2 章の命題(命題 6.2[ツールと権限])により、第 2 章の模型が扱う 3 つのモード(default・acceptEdits・bypassPermissions)では、AA は deny 規則にマッチしない呼び出しの全体に等しく、モードに依りません。確認を拒否に変える dontAsk モードはこの模型の外で、そこでは prompt\mathrm{prompt} にあたる呼び出しが実行されないので、実行されうる呼び出しはこれより狭くなります。

定理 3.2(能力による上界と、その達成)✓

第 1 章 のエージェントループの模型で、関門を「Dμ,R(q)=runD_{\mu,R}(q) = \mathrm{run} なら実行する、block\mathrm{block} なら拒否する、prompt\mathrm{prompt} なら利用者の答えに従う」と定める。ツールの判定を置き換える拡張(前章で触れた mod)は導入されていないとする。このとき次が成り立つ。

  1. モデルがどんな写像であっても、また文脈にどんな入力が入っても、実行されるツール呼び出しはすべて AA に属する。利用者が 1 回も承認しなければ、実行される呼び出しはすべて ArunA_{\mathrm{run}} に属する。
  2. (達成)任意の q∈Arunq \in A_{\mathrm{run}} について、qq が利用者の関与なしに実行されるようなモデルが存在する。
  3. (単調性)RR に deny 規則を足した規則集合を R′R' とすると、R′R' のもとでの AA と ArunA_{\mathrm{run}} は、RR のもとでのそれらに含まれる。
証明(定理 3.2)

1: 模型では、ツールが実行されるのは、関門が実行を選んだときだけです。関門が実行を選ぶのは、Dμ,R(q)=runD_{\mu,R}(q) = \mathrm{run} のときか、Dμ,R(q)=promptD_{\mu,R}(q) = \mathrm{prompt} で利用者が承認したときで、どちらの場合も Dμ,R(q)≠blockD_{\mu,R}(q) \ne \mathrm{block}、すなわち q∈Aq \in A です。判定 Dμ,RD_{\mu,R} は規則の集合とモードと呼び出しだけで決まる写像で(定理 3.4[ツールと権限])、文脈の内容やモデルの出力のうち、判定に入るのは呼び出し qq そのものだけです。したがって、この包含はモデルと文脈に依らずに成り立ちます。利用者が承認しなければ、実行されるのは Dμ,R(q)=runD_{\mu,R}(q) = \mathrm{run} の呼び出しだけで、ArunA_{\mathrm{run}} に属します。

2: q∈Arunq \in A_{\mathrm{run}} を取ります。入力のメッセージ列に依らず「qq を 1 つ呼ぶ応答」を返す定数写像をモデルとします。模型ではモデルは任意の写像なので、これはモデルとして許されます。最初のモデルの呼び出しで qq が出力され、Dμ,R(q)=runD_{\mu,R}(q) = \mathrm{run} なので、確認なしで実行されます。

3: deny 規則を足すと、deny にマッチする呼び出しの集合は増えるか変わらないかです。判定は deny を最初に調べるので、RR のもとで block\mathrm{block} だった呼び出しは R′R' のもとでも block\mathrm{block} で、AA は増えません。ArunA_{\mathrm{run}} についても、deny 規則を足して許可される呼び出しが増えることはありません(命題 3.6[ツールと権限])。

1 は、公式ドキュメント(“Configure permissions”)の「権限規則は、モデルではなく Claude Code が強制する」という記述を、模型の上で言い直したものです。プロンプトや指示ファイルの指示は、Claude Code が何を許すかを変えません。

2 は、この上界が見かけのものではないことを示しています。「モデルは普通そんなことをしない」という期待は、上界を下げません。確認なしで実行できる集合 ArunA_{\mathrm{run}} に入っている行為は、モデルの出力しだいで実行されます。そしてモデルの出力は、文脈に入った内容に影響されます。したがって、最悪の場合に起こりうることは、ArunA_{\mathrm{run}}(承認を含めれば AA)の行為の列で実現できることのすべてです。

3 は、設計する側にできることを示しています。deny 規則を足す、モードを狭いものにする、ツールを与えない、という操作は、どれも上界を下げます。これが最小権限(その仕事に必要な能力だけを与える)の根拠です。Agent SDK の公式ドキュメントは、最小権限の例として、必要なディレクトリだけを読み取り専用で見せる、ネットワークを特定の送信先に限る、資格情報を直接渡さない、を挙げています。

注意 3.3(模型の仮定と、上界に入らないもの)

  • mod。公式ドキュメントによれば、Claude Code の中で自分のコードを動かす種類のプラグイン(mod)は、ツールの判定に答えを返し、条件によっては規則やフックの判定を置き換えられます。定理に「導入されていない」という仮定を入れたのはこのためです。組織の管理設定がある環境では、deny 規則が既定で優先すると書かれています。
  • auto モード。定理は、判定 Dμ,RD_{\mu,R} が規則とモードと呼び出しだけで決まる、という第 2 章の模型の上のものです。auto モードでは、規則で決まらない行為を分類器(別のモデル)が審査します。公式ドキュメントによれば、分類器への要求には利用者のメッセージや CLAUDE.md の内容が含まれるので、その判断は呼び出しだけの関数ではありません。したがって auto モードでは、確認なしで実行される集合 ArunA_{\mathrm{run}} を規則とモードから前もって書き出すことはできません。文脈に依らずに成り立つ上界は AA(deny 規則にマッチしない呼び出しの全体)で、分類器は 5 節の確率的な層として数えます。
  • 行為の効果。AA は呼び出しの集合で、効果の集合ではありません。許可されたシェルコマンドは、利用者のアカウントが書ける場所ならどこにでも書けます。公式ドキュメントは、作業ディレクトリの境界は権限の確認であって OS による強制ではない、と明記しています。効果を囲うのはサンドボックスの役目です(4.3 節)。
  • 規則の書き方。規則はコマンドの文字列に対する構文的な照合なので、同じ効果を持つ別の書き方がマッチを外れることがあります(命題 9.1[ツールと権限])。「危険な行為の集合」と「deny にマッチする集合」は一致しません。
  • 自動で動くプログラム。フックや MCP サーバのプロセスは、ツール呼び出しではないので QQ に入っていません。これらは 6 節で扱います。

3.2. 入力の検査だけでは足りない

Section titled “3.2. 入力の検査だけでは足りない”

能力を絞る代わりに、「有害な行為を引き起こす入力」を入口で見つけて取り除く、という考えがあります。これは有用な層の 1 つですが、それだけに頼ることはできません。以下の命題は、その理由を計算可能性の言葉で述べます。ねらいは、入力の文面だけを見る完璧な検査は期待できない、と言うことです。証明は、ライスの定理(プログラムの振る舞いについての自明でない性質は、一般には判定できない)に帰着させます。式を追わなくても、命題の下の注意書きを読めば、何が言えて何が言えないかは分かります。

命題 3.4(入力の検査の限界)✓

入力(文字列)と呼び出し(QQ の元)をそれぞれ自然数で符号化し、モデルを「入力から呼び出しへの部分計算可能な写像」とみなす模型を考える。有害とみなす呼び出しの集合を BB(∅≠B⊊Q\varnothing \ne B \subsetneq Q、所属は決定可能)とする。φ0,φ1,…\varphi_0, \varphi_1, \ldots を部分計算可能関数の受理可能な番号付けとし、その万能関数 (e,y)↦φe(y)(e, y) \mapsto \varphi_e(y) は部分計算可能であるとする。

  1. 番号 ee を入力として「φe(0)\varphi_e(0) が定義されて BB に属するか」を判定するアルゴリズムは存在しない。
  2. モデル UU を U(x)=φx(0)U(x) = \varphi_x(0) と定めると(万能関数により、UU は部分計算可能な写像である)、UU に有害な呼び出しをさせる入力の集合 HarmU={x:U(x)∈B}\mathrm{Harm}_U = \{x : U(x) \in B\} は決定不能である。
  3. したがって、入力だけを見て「止める」「通す」を決めるどんな決定可能な検査 KK(止める入力の集合)についても、K≠HarmUK \ne \mathrm{Harm}_U である。すなわち、UU に対しては、有害な入力を通す(見逃し)か、無害な入力を止める(誤検出)かの少なくとも一方が必ず起こる。
証明(命題 3.4)

1: 部分計算可能関数の集合 P={f:f(0) が定義されて f(0)∈B}\mathcal{P} = \{f : f(0) \text{ が定義されて } f(0) \in B\} を考えます。B≠∅B \ne \varnothing なので b∈Bb \in B を取ると、常に bb を返す定数関数は P\mathcal{P} に属し、P≠∅\mathcal{P} \ne \varnothing です。どこでも定義されない関数は P\mathcal{P} に属さないので、P\mathcal{P} はすべての部分計算可能関数の集合とは一致しません。よって P\mathcal{P} は非自明で、ライスの定理(定理 5.1)[AI時代のITエンジニアの生存戦略] により、添字集合 IP={e:φe∈P}I_{\mathcal{P}} = \{e : \varphi_e \in \mathcal{P}\} は決定不能です。これは 1 の主張そのものです。

2: x∈HarmUx \in \mathrm{Harm}_U は、U(x)=φx(0)U(x) = \varphi_x(0) が定義されて BB に属すること、すなわち φx∈P\varphi_x \in \mathcal{P}、すなわち x∈IPx \in I_{\mathcal{P}} と同値です。よって HarmU=IP\mathrm{Harm}_U = I_{\mathcal{P}} で、1 により決定不能です。

3: KK は決定可能、HarmU\mathrm{Harm}_U は決定不能なので、K≠HarmUK \ne \mathrm{Harm}_U です。2 つの集合が異なるので、HarmU\mathrm{Harm}_U に属して KK に属さない入力(有害なのに通す)か、KK に属して HarmU\mathrm{Harm}_U に属さない入力(無害なのに止める)が、少なくとも 1 つあります。

この命題は、健全な静的検査が必ず安全なプログラムの一部を拒否するという定理(定理 5.6[プログラミング言語論])と同じ形をしています。検査の健全性と完全性(定義 6.1[事例研究])の言葉で言えば、モデル UU に対する決定可能な検査のうち、有害な入力をすべて止める検査は、無害な入力も止めることになり、無害な入力をすべて通す検査は、有害な入力も通すことになります。

注意 3.5(この命題が言っていること・いないこと)

これは模型の上の限界で、実在のモデルや検査器の性能についての主張ではありません。UU は「入力をプログラムとして解釈して実行する」という極端なモデルで、実在のモデルがそうだと言っているのではありません。命題の 3 は、この UU についての主張です。モデル MM がすべての入力で値を返す計算可能な写像なら、HarmM={x:M(x)∈B}\mathrm{Harm}_M = \{x : M(x) \in B\} は、MM を実際に動かして出力が BB に属するかを調べれば決定できます(BB の所属は決定可能と仮定しています)。つまり、命題は「個々のモデルごとに完全な検査が原理的に存在しない」とは言っていません。命題が示すのは、モデルの振る舞いを使わずに「入力の文面だけを見て、モデルに何をさせるかを完全に判定する」検査を、どんなモデルにも通用する一般的な保証として期待できない、ということです。モデルを動かして確かめる検査は、モデルの呼び出しと同じだけの費用がかかり、出力が揺らぐ(サンプリングする)モデルでは 1 回の試行で結果が決まりません。実用の検査は、よくある形を高い割合で見つけるという意味で役に立ちます。公式資料も、入力やツールの出力を別のモデル呼び出しで検査する方法を、防御の層の 1 つとして紹介しています。ただしそれは確率的な層で、5 節の計算の対象になります。入力の検査が完全になりえない以上、定理 3.2 の「能力を絞る」側の対処と組み合わせる必要があります。

4. 情報の流れ:外へ出る経路ができる条件

Section titled “4. 情報の流れ:外へ出る経路ができる条件”

被害の中で、とくに取り返しがつかないのが、非公開の情報(資格情報、未公開のコードなど)が外部に送られることです。どういう構成でその経路ができるかを、模型で調べます。

定義 4.1(情報の流れの模型)↗

1 回のループの実行を、信頼できる入力 tt、信頼できない入力 uu(外部の内容の作者が決める)、非公開の情報 ss、モデル MM(メッセージ列から呼び出しへの写像)で決まるものとする。攻撃者は uu を自由に選べるが、ss を知らず、tt と MM を変えられないとする。能力 ArunA_{\mathrm{run}} について、次の 3 つの条件を考える。

  • (a) 非公開の情報を読む能力: ss を結果として文脈に入れる呼び出しが ArunA_{\mathrm{run}} にある。
  • (b) 信頼できない入力の経路: uu を結果として文脈に入れる呼び出しが ArunA_{\mathrm{run}} にある(または uu が初めから文脈に入る)。
  • (c) 外部へ送る能力: 引数に含めた文字列を外部の主体に届ける呼び出しが ArunA_{\mathrm{run}} にある。

実行の中で外部に届いた文字列の列を Ext(M,t,u,s)\mathrm{Ext}(M, t, u, s) と書く。模型では次を仮定する。利用者は確認に 1 回も承認を与えない(したがって、実行されるのは ArunA_{\mathrm{run}} の呼び出しだけである)。(a) の呼び出しを実行しない限り ss は文脈に入らず、(a) でない呼び出しの結果と効果は ss に依らない。(b) の経路を通らない限り uu は文脈に入らず、(b) でない呼び出しの結果と効果は uu に依らない。外部に届くのは (c) の呼び出しの引数に含めた文字列だけで、(c) の呼び出しを実行しない限り何も外部に届かない。

命題 4.2(外へ出る経路ができる条件)✓

情報の流れの模型(定義 4.1) で次が成り立つ。

  1. (a)・(b)・(c) がすべて成り立つならば、あるモデル MM と信頼できない入力 uu があって、どんな ss についても Ext(M,t,u,s)\mathrm{Ext}(M, t, u, s) に ss が現れる。
  2. (a) が成り立たなければ、どんな MM、tt、uu についても、Ext(M,t,u,s)\mathrm{Ext}(M, t, u, s) は ss に依らない。
  3. (b) が成り立たなければ、どんな MM、tt、ss についても、Ext(M,t,u,s)\mathrm{Ext}(M, t, u, s) は uu に依らない。
  4. (c) が成り立たなければ、Ext(M,t,u,s)\mathrm{Ext}(M, t, u, s) は常に空である。
証明(命題 4.2)

1: uu を「印」となる決まった文字列を含むものとし、モデル MM を次の写像と定めます。文脈に印が無ければ (b) の呼び出しを出力する。文脈に印があり、まだ (a) の呼び出しの結果が無ければ (a) の呼び出しを出力する。(a) の結果 ss が文脈にあれば、ss を引数に含めた (c) の呼び出しを出力する。そのあとはツールを呼ばない応答を返す。3 つの呼び出しはどれも ArunA_{\mathrm{run}} に属するので、確認なしで実行されます。実行は「(b) で uu が入る → (a) で ss が入る → (c) で ss が外部に届く」と進み、Ext\mathrm{Ext} に ss が現れます。MM の定義は ss の値を使っていないので、これはどんな ss についても成り立ちます。

2: (a) の呼び出しが ArunA_{\mathrm{run}} に無ければ、利用者が承認を与えないという仮定と 定理 3.2 の 1 により、それは実行されません。模型の仮定により、ss は文脈に入りません。ステップの数についての帰納法で、各時点のメッセージ列が ss に依らないことを示します。初めのメッセージ列は tt(と、場合により uu)で決まり、ss に依りません。ある時点のメッセージ列が ss に依らなければ、モデルの出力(メッセージ列の関数)も ss に依らず、実行される呼び出しも、その結果(ss を読まない呼び出しの結果)も ss に依りません。したがって次のメッセージ列も ss に依りません。外部に届く文字列は (c) の呼び出しの引数で、モデルの出力の一部なので、ss に依りません。

3: (b) が成り立たなければ、uu は文脈に入りません。2 と同じ帰納法で、各時点のメッセージ列が uu に依らないことが分かり、Ext\mathrm{Ext} も uu に依りません。

4: (c) の呼び出しが ArunA_{\mathrm{run}} に無ければ実行されず、模型の仮定により外部には何も届きません。

2 から 4 は、3 つの条件のどれを欠いても、「攻撃者が uu を選ぶことで ss を外部に出させる」ことが、模型の上ではできないことを示しています。2 では外に出るものが ss と無関係になり、3 では攻撃者の選択が実行に影響せず、4 では何も外に出ません。1 は、3 つがそろうと、定理 3.2 の達成の議論と同じく、経路が実際に存在することを示しています。

注意 4.3(模型に入っていない経路)

  • 3 が言うのは「攻撃者の選択に依らない」ことで、「漏れない」ことではありません。モデルが自分の誤りで非公開の情報を外に送ることは、(b) が無くても起こりえます。公式資料は、意図しない行為の原因として、プロンプトインジェクションとモデルの誤りの 2 つを挙げています。
  • 利用者自身が出力を外部に貼る、画面を共有する、といった経路は対象外です。
  • (c) は「引数を外部に届ける呼び出し」をすべて含みます。ウェブの取得は URL に文字列を載せられるので (c) にあたりえます。リポジトリへの push、課題管理への書き込み、メールの送信なども同じです。どの呼び出しが (c) にあたるかの分類は、設計する側が行うもので、分類を誤れば命題の前提が崩れます。
  • (a) には、資格情報のファイルだけでなく、環境変数や、文脈にすでに入っている内容も含まれます。
  • 1 つの呼び出しが、非公開の情報を読むことと外部へ送ることを内部で両方行う場合があります(任意のプログラムを動かせるシェルコマンドが典型です)。このとき ss は文脈を通らずに外へ出るので、模型の「(a) でない呼び出しの効果は ss に依らない」という仮定を保つには、そのような呼び出しを (a) と (c) の両方にあたるものとして分類する必要があります。4.2 節の検査器でサンドボックスなしのシェルを 3 つとも「開」にしているのは、このためです。
  • 命題は、利用者が承認を与えない実行についてのものです。確認つきの呼び出しを利用者が承認すれば、A∖ArunA \setminus A_{\mathrm{run}} の呼び出しも実行されるので、(a)・(b)・(c) は AA について数え直す必要があります。

公開のウェブページを要約させる課題を考えます。ページの中に、利用者が頼んでいない「指示の形をした文」が含まれているとします(文面は問いません)。この文は、取得の結果として文脈に入ります(経路 (b))。このとき何が起こりうるかは、ほかにどの能力があるかで決まります。

次の検査器は、構成(確認なしで実行できる行為の一覧)に「読む・入る・送る」のラベルを付け、(a)・(b)・(c) のどれが開いているかを表にします。Read(repo) のような名前は「どの道具を、どの範囲に使うか」を表し、各行の 3 つの真偽値は、その行為が (a) 非公開の情報を読むか、(b) 信頼できない入力を文脈に入れるか、(c) 外部へ送れるか、に対応します。たとえばリポジトリのファイルは他人が書いたものを含みうるので (b) が真、ウェブの取得は URL に文字列を載せて送れるので (c) が真、と付けています。ラベルは例のために私が付けたもので、実物の設定を検査する道具ではありません。

# 構成(許される行為の集合 A)から、(a) 非公開の情報を読む (b) 信頼できない入力が入る
# (c) 外部へ送る、のどれが開いているかを判定する検査器。模型であり、実物の設定の検査器ではない。
LABELS = { # 行為 -> (非公開を読む, 信頼できない入力を文脈に入れる, 外部へ送る)
"Read(repo)": (True, True, False), # リポジトリの中のファイルは他人が書きうる
"Read(~/.ssh)": (True, False, False),
"Edit(repo)": (False, False, False),
"WebFetch(any)": (False, True, True), # URL に情報を載せて送れる
"WebFetch(docs only)": (False, True, False), # 模型の仮定: 許可した先は受け取った情報を攻撃者に渡さない
"Bash(sandbox, D={})": (True, True, False), # 許可ドメインが空(模型の仮定: 外への接続はあとから許されない)
"Bash(unsandboxed)": (True, True, True),
"mcp(issue tracker)": (True, True, True),
}
CONFIGS = {
"1 読み取り専用の調査": ["Read(repo)"],
"2 ネットワークなしの編集": ["Read(repo)", "Edit(repo)", "Bash(sandbox, D={})"],
"3 外部への送信を伴う作業": ["Read(repo)", "Edit(repo)", "Bash(unsandboxed)", "WebFetch(any)"],
"4 文書の参照つきの編集": ["Read(repo)", "Edit(repo)", "Bash(sandbox, D={})", "WebFetch(docs only)"],
}
def check(actions):
a = any(LABELS[x][0] for x in actions)
b = any(LABELS[x][1] for x in actions)
c = any(LABELS[x][2] for x in actions)
return a, b, c
mark = lambda v: "開" if v else "閉"
print("構成 (a) (b) (c) 流出の経路")
for name, actions in CONFIGS.items():
a, b, c = check(actions)
print(f"{name:<22}\t{mark(a)} {mark(b)} {mark(c)} {'あり' if a and b and c else 'なし(模型の上で)'}")

実行した出力(Python 3.9、2026-10-10 実行):

構成 (a) (b) (c) 流出の経路
1 読み取り専用の調査 開 開 閉 なし(模型の上で)
2 ネットワークなしの編集 開 開 閉 なし(模型の上で)
3 外部への送信を伴う作業 開 開 開 あり
4 文書の参照つきの編集 開 開 閉 なし(模型の上で)
構成開いている条件追加で必要な対策
1 読み取り専用の調査(a)・(b)(c) が無いので経路は無い。ただし調査の結果(最終の応答)そのものが信頼できない入力の影響を受けうるので、結果を使う側で確かめる
2 ネットワークなしの編集(a)・(b)シェルコマンドの (c) をサンドボックスで閉じている。ファイル用のツールや MCP ツールに (c) が無いことを権限規則で別に確かめる。編集されたファイルを確かめる(完全性)
3 外部への送信を伴う作業(a)・(b)・(c)3 つがそろう。送信を伴う呼び出しを確認つきにする(ArunA_{\mathrm{run}} から外す)、読める範囲から資格情報を外す、信頼できない内容を扱う部分を別の構成に分ける、のどれかで 1 つを閉じる

構成 4 の「許可した先は受け取った情報を攻撃者に渡さない」は、模型に入れた仮定です。許可した送信先が、受け取った内容を第三者が読める形で公開する場所なら、(c) は開いています。

サブエージェントは、構成を分ける道具になります。前々章の定理(定理 5.3[文脈を保つ・減らす・分ける])により、子が読んだ内容のうち親に渡るのは最終の応答だけです。信頼できない内容を読む仕事を、(a) と (c) を持たない子に任せれば、子の中では経路ができません。ただし最終の応答は親の文脈に入るので、親から見ればそれは (b) の経路の 1 つです。分離は経路を細くしますが、無くしはしません。

4.3. サンドボックスで送信先を囲う

Section titled “4.3. サンドボックスで送信先を囲う”

(c) を閉じる手段のうち、モデルの出力に依らず、設定によっては権限の判定にも依らないのが、OS が強制するサンドボックスです。

命題 4.4(サンドボックス下のシェルコマンドの送信先)✓

第 2 章 のサンドボックスの模型で、接続できるホストの集合を DD とする設定のもとで実行されたシェルコマンドについて、次が成り立つ。ここで「接続できるホストは DD だけ」は模型の仮定で、DD の外のホストへの接続が、利用者の承認や権限モードによってあとから許されることは無いとする(実物でこの仮定にあたる設定は、下の「許可ドメインの外のホスト」の項を参照)。

  1. コマンドとその子プロセスが接続できた先は、すべて DD に属する。これは、権限の判定がどんな写像であっても、モデルが何を出力しても成り立つ。とくに D=∅D = \varnothing なら、サンドボックス下のシェルコマンドはどこにも接続できない。
  2. サンドボックスの外で実行される呼び出し(ファイル用やウェブ用のツール、MCP ツール、サンドボックスなしで実行されるコマンド)には 1 が及ばない。それらの (c) は、権限規則で別に閉じる必要がある。
証明(命題 4.4)

1: 第 2 章の命題(命題 8.2[ツールと権限])の 1 により、サンドボックス下で実行されたシェルコマンドの効果は、許可された操作の集合に含まれ、これは関門の判定とモデルの出力に依りません。許可された接続は DD のホストへのものだけなので、効果を持った接続の先は DD に属します。D=∅D = \varnothing なら、許可された接続が無いので、接続はどれも効果を持ちません。

2: 同じ命題の 2 により、サンドボックスの外で実行される呼び出しには 1 の包含が及びません。それらが実行されるかどうかを決めるのは関門だけなので、定理 3.2 により、ArunA_{\mathrm{run}} から外すこと(deny 規則を足す、確認つきにする)で閉じます。

公式ドキュメント(“Configure the sandboxed Bash tool”、2026-10-10 確認)は、この 2 つの層の違いを次のように述べています。権限の判定は、コマンドが走る前に、コマンドの文字列(auto モードでは分類器の判断も)にもとづいて行われる。サンドボックスの境界は、走っているプロセスに対して OS が強制するので、モデルが何を走らせることにしたかに関係なく成り立ち、許可されたコマンドがその名前から想像される以上のことをした場合にも成り立つ。

同じページは、適用範囲と限界も明記しています。命題の模型は、これらを単純化しています。

  • 既定では無効。サンドボックスは既定で無効で、有効にする操作が要ります。ネイティブの Windows ではサンドボックスなしで実行されます。
  • 許可ドメインの外のホスト。サンドボックス下のコマンドが許可ドメインに無いホストへ接続しようとしたとき、既定では、どうなるかは権限モードで決まります。対話的なセッションでは、Manual モードなどでは利用者に確認が出て、auto モードでは原則として拒否され、dontAsk モードでは拒否され、bypassPermissions モードでは確認なしで許可されます。許可ドメインを厳格に適用する設定(strictAllowlist、または組織の管理設定の allowManagedDomainsOnly)を有効にすると、どの権限モードでもプロキシが接続を拒否します。命題 4.4 の 1 の「権限の判定に依らない」は、この厳格な設定のもとでの性質です。既定の設定では、DD の外への接続は、確認に対する人間の承認(確率的な層)か、モードの選び方に依ります。
  • 覆うのはシェルコマンドだけ。組み込みのファイル用・ウェブ用のツール、コマンドのフック、利用者の機械の上の MCP サーバなどは、サンドボックスの外で動きます。サンドボックスの読み取りの拒否は Read ツールを止めず、許可ドメインは WebFetch を制限しない、と書かれています。
  • 外で動くコマンドがある。除外に指定したコマンドはサンドボックスの外で動きます。サンドボックスの中で失敗したコマンドを、モデルがサンドボックスなしで再試行することがあり(誰が承認するかは権限モードで決まる)、設定でこの再試行を禁じられます。
  • 読み取りの既定は広い。既定では、書き込みは作業ディレクトリなどに限られますが、読み取りは機械の大部分(資格情報のファイルを含む)に及びます。(a) を閉じるには、読み取りの拒否や資格情報の保護を別に設定します。
  • ホスト名による判定。組み込みのプロキシは、要求されたホスト名にもとづいて許可を決め、既定では暗号化された通信の中身を検査しません。広いドメインを許可すると情報の流出の経路になりうること、より強い保証が要る場合は通信を検査する独自のプロキシを構成することが書かれています。
  • 設定で弱まる。特定の Unix ソケットへの接続を許す、実行ファイルの置き場所や設定ファイルへの書き込みを許す、などの設定は、サンドボックスの迂回や権限の昇格につながりうる、と注意されています。
  • ファイルとネットワークの両方が要る。ネットワークの分離が無ければ、操作されたエージェントが秘密のファイルを外に送れる。ファイルシステムの分離が無ければ、システムの資源を書き換えてネットワークへの経路を得られる。したがって両方が必要である、と書かれています。

同じページの「Security limitations」の節の前には、サンドボックスは危険を減らすが、完全な分離の境界ではない、という断り書きがあります。すべてを 1 つの境界の中に入れたい場合は、Claude Code のプロセスそのものをコンテナや仮想マシンの中で動かす方法が案内されています。

定義 5.1(防御の層)↗

防御の層とは、危険な行為が実行に至る途中で、それを止める機会を持つ仕組みをいう。層を次の 2 種類に分ける。

  • 決定的な層: 対象とする行為の集合 CC が決まっていて、CC に属する行為を必ず止めるもの。deny 規則(マッチする呼び出しを必ず止める)、OS が強制するサンドボックス(許可されていない操作を必ず失敗させる)、ブロックするフック。
  • 確率的な層: 危険な行為を止めるが、ある確率で見逃すもの。モデル自身の判断、分類器による審査、入力や出力の検査、人間による承認。危険な行為 1 つを見逃す確率を、その層の見逃しの確率という。

複数の層を重ねることを多層防御という。

公式ドキュメントが挙げる Claude Code の保護を、この分類で並べます(“Security”・“Choose a permission mode”、2026-10-10 確認)。

保護種類公式ドキュメントの記述の要点
権限規則(deny・ask)決定的どのモードでも適用される
サンドボックス決定的(シェルコマンドの効果について)4.3 節
フォルダの信頼の確認決定的(未確認のフォルダの一部の設定を使わない)対話的なセッションで、信頼していないフォルダで起動したときに確認が出る
マッチしないコマンドは承認を要する決定的(Manual モードで)許可の規則に当てはまらないものは既定で確認する(fail-closed)
解析しきれないコマンドの確認決定的(Manual モードで)完全に解析できない Bash コマンドは、部分的な allow 規則があっても確認する
ネットワークを使うコマンドの扱い決定的(既定の集合について)curl や wget のように内容を取得するコマンドは、既定では自動で承認されない
取得したページの処理確率的多くの取得で、ページに対して別のモデル呼び出しを行い、モデルは生のページではなくその答えを受け取る
auto モードの分類器確率的別のモデルが、実行の前に行為を審査する
人間による承認確率的Manual モードでは、機微な操作に明示の承認が要る

auto モードの分類器について、公式ドキュメントは次のことを述べています。行為は決まった順に判定され、規則にマッチするものは(列挙された例外を除いて)即決され、読み取りと作業ディレクトリ内の編集は自動で承認され、残りが分類器に送られます。分類器への要求では、ツールの結果は取り除かれるので、ファイルやウェブページの中の敵対的な内容が分類器を直接操作することはできない、と書かれています。分類器が続けて 3 回、または合計で 20 回ブロックすると、auto モードは一時停止し、確認を求める動作に戻ります(この 2 つのしきい値は設定できません)。分類器の判定の基準の詳細や誤りの率は、この記事では扱いません。

命題 5.2(多層防御の見逃しの確率)✓

ある危険な行為が、kk 個の層を順に通るとする。層 ii がこの行為を見逃す事象を EiE_i、その確率を εi=P(Ei)\varepsilon_i = P(E_i) とする。

  1. E1,…,EkE_1, \ldots, E_k が独立ならば、すべての層を通り抜ける確率は ∏i=1kεi\prod_{i=1}^{k} \varepsilon_i である。
  2. 独立でない場合、積にはならないことがある。確率 qq で「すべての層が同時に見逃す」原因が起こり、それが起こらない条件のもとで各層が独立に確率 εi\varepsilon_i で見逃すとすると、通り抜ける確率は q+(1−q)∏iεi≥qq + (1 - q)\prod_{i} \varepsilon_i \ge q で、層をいくつ重ねても qq を下回らない。
  3. ある層がこの行為について決定的(必ず止める)ならば、他の層の確率や独立性に関係なく、通り抜ける確率は 00 である。
証明(命題 5.2)

1: 通り抜けるのは、すべての層が見逃すとき、すなわち事象 E1∩⋯∩EkE_1 \cap \cdots \cap E_k です。独立性の定義(定義 5.6[確率])により、その確率は P(E1)⋯P(Ek)=∏iεiP(E_1) \cdots P(E_k) = \prod_i \varepsilon_i です。

2: 共通の原因が起こる事象を GG とします。P(G)=qP(G) = q で、GG のもとではすべての層が見逃すので、通り抜ける確率は 11 です。GG が起こらない条件のもとでは、1 と同じ計算で ∏iεi\prod_i \varepsilon_i です。場合を分けて足すと q⋅1+(1−q)∏iεiq \cdot 1 + (1 - q) \prod_i \varepsilon_i で、第 2 項は 00 以上なので qq 以上です。

3: その層が見逃す事象の確率は 00 です。通り抜ける事象は、この層が見逃す事象に含まれるので、確率は 00 以下、したがって 00 です。

2 は、冗長化したレプリカが同じノードに載っていると、ノードの故障の確率より可用性を上げられない、という結果(系 7.3[Docker と Kubernetes])と同じ式です。独立な場合の 1 は、定理 7.1[Docker と Kubernetes] の pNp^N に対応します。

防御の層で「共通の原因」にあたるのは、同じ入力が複数の層を同時に破る場合です。たとえば、モデル自身の判断と、同じ文脈を読む別のモデルによる審査は、同じ内容に同じように影響されるおそれがあり、独立とは言いにくい組です。分類器への要求からツールの結果を取り除くという、前節で見た設計は、審査の層が見る入力を主モデルが見る入力と変えることで、この共通の原因を減らす工夫だと読めます。

独立な場合穴がそろわず、通り抜けない共通の原因がある場合同じ位置の穴が貫通する
層を重ねた壁。独立な場合は、穴の位置が層ごとにずれるので貫通しない。共通の原因がある場合は、すべての層に同じ位置の穴が開き、貫通する。

3 が、決定的な層を別に扱う理由です。確率的な層をいくつ重ねても確率は 00 になりませんが、決定的な層は、その対象については確率を 00 にします。ただし「対象については」という限定が要です。deny 規則が止めるのはマッチする呼び出しだけで、サンドボックスが囲うのはシェルコマンドの効果だけです。対象の外では、決定的な層は何も保証しません。

確率的な層は、1 回あたりの見逃しが小さくても、試行が重なると破れます。

命題 5.3(確率的な審査と繰り返しの試行)✓

危険な行為の試行のそれぞれを、確率的な審査が独立に、確率 ε\varepsilon(0<ε<10 \lt \varepsilon \lt 1)で見逃し、確率 1−ε1 - \varepsilon で止めるとする。

  1. nn 回の試行のうち少なくとも 1 回を見逃す確率は 1−(1−ε)n1 - (1 - \varepsilon)^n で、n→∞n \to \infty のとき 11 に近づく。
  2. 「kk 回止めたら、それ以上は自動で審査せず、人間の確認に回す」という規則を加えると、人間の確認に回る前に見逃しが起こる確率は 1−(1−ε)k1 - (1 - \varepsilon)^k で、試行の回数に依らずこの値を超えない。
証明(命題 5.3)

1: 1 回も見逃さないのは、nn 回すべてを止めるときで、独立性によりその確率は (1−ε)n(1 - \varepsilon)^n です(定理 4.3[確率] で、成功を「止める」、成功の回数を nn とした場合)。少なくとも 1 回見逃す確率はその余事象で 1−(1−ε)n1 - (1 - \varepsilon)^n です。0<1−ε<10 \lt 1 - \varepsilon \lt 1 なので、n→∞n \to \infty で (1−ε)n→0(1 - \varepsilon)^n \to 0、したがって確率は 11 に近づきます。これは、失敗率 θ\theta の性質を NN 回試して少なくとも 1 回失敗を見つける確率 1−(1−θ)N1 - (1 - \theta)^N(定理 3.2[性質ベーステスト])と同じ計算で、見つける側と見逃す側が入れ替わっただけです。

2: 規則のもとでは、審査の過程は「最初の見逃しが起こる」か「kk 回目の停止が起こる」かのどちらか早いほうで終わります。人間の確認に回る前に見逃しが起こらないのは、最初の kk 回の試行がすべて止められるときで、その確率は (1−ε)k(1 - \varepsilon)^k です。よって、見逃しが先に起こる確率は 1−(1−ε)k1 - (1 - \varepsilon)^k です。この値は、試行をどれだけ続けようとしても変わりません(kk 回止められた時点で、自動の審査が終わるため)。

2 の上界は、人間の確認に回るまでの 1 区間についてのものです。確認のあとで自動の審査が再開されるなら、区間ごとに同じ上界が当てはまり、区間の数とともに全体の見逃しの確率は増えます。

1 は、操作されたモデルが、止められても形を変えて同じことを試み続ける、という状況の模型です。nn に上限が無ければ、どんなに小さい ε\varepsilon でも、いずれ見逃しが起こります。同じ計算は、確率的に失敗する検査を何度も通すとどこかで失敗する、という結果(定理 4.1[継続的インテグレーション])にも現れます。

2 は、公開されている「連続 3 回、または合計 20 回のブロックで確認に戻る」という仕組みの働きを説明します。この仕組みは ε\varepsilon を小さくするのではなく、自動の審査だけで済まされる試行の回数を抑えます。危険な試行だけが続く場合は k=3k = 3 で、上界は 1−(1−ε)31 - (1 - \varepsilon)^3(ε\varepsilon が小さければ約 3ε3\varepsilon)です。無害な行為を挟んで連続の数え直しが起こる場合でも、合計の上限により k=20k = 20 で、上界は 1−(1−ε)201 - (1 - \varepsilon)^{20} です。公式ドキュメントによれば、確認を出す先の無い非対話の実行では、しきい値に達してもその行為が実行されないだけで実行全体は止まらないので、この上界は対話的なセッションについてのものです。

ε\varepsilon の値は公開されていないので、記号のまま扱います。次の数値は、式の形を見るための仮の値 ε=0.01\varepsilon = 0.01 によるもので、実物の値ではありません。

import math
eps = 0.01 # 仮の値。公開されている数値ではない
for n in (10, 100, 1000):
print(f"n = {n:>4}: 1 - (1 - eps)^n = {1 - (1 - eps) ** n:.4f}")
print("1/2 を超える最小の n:", math.ceil(math.log(0.5) / math.log(1 - eps)))
for k in (3, 20): # k 回ブロックされたら人間の確認に戻る場合
print(f"ブロック {k:>2} 回で確認に戻る: 見逃しの確率は高々 1 - (1 - eps)^{k} = {1 - (1 - eps) ** k:.4f}")
layers = [0.1, 0.1, 0.05]
prod = 1.0
for e in layers:
prod *= e
print("独立な 3 層 (0.1, 0.1, 0.05) をすべて通り抜ける確率:", round(prod, 6))
q = 0.02 # 3 層が同時に破れる入力の割合(仮の値)
print("共通の原因 q = 0.02 があるとき:", round(q + (1 - q) * prod, 6), " (q 以上)")
h0, c, r = 0.02, 0.004, 0.3 # 承認疲れの模型の仮の値
for m in (5, 20, 50, 100):
h = min(1.0, h0 + c * m)
print(f"確認 {m:>3} 件: 1 件あたりの見逃し {h:.3f} 見逃しの期待件数 {r * m * h:.2f}")

実行した出力(Python 3.9、2026-10-10 実行):

n = 10: 1 - (1 - eps)^n = 0.0956
n = 100: 1 - (1 - eps)^n = 0.6340
n = 1000: 1 - (1 - eps)^n = 1.0000
1/2 を超える最小の n: 69
ブロック 3 回で確認に戻る: 見逃しの確率は高々 1 - (1 - eps)^3 = 0.0297
ブロック 20 回で確認に戻る: 見逃しの確率は高々 1 - (1 - eps)^20 = 0.1821
独立な 3 層 (0.1, 0.1, 0.05) をすべて通り抜ける確率: 0.0005
共通の原因 q = 0.02 があるとき: 0.02049 (q 以上)
確認 5 件: 1 件あたりの見逃し 0.040 見逃しの期待件数 0.06
確認 20 件: 1 件あたりの見逃し 0.100 見逃しの期待件数 0.60
確認 50 件: 1 件あたりの見逃し 0.220 見逃しの期待件数 3.30
確認 100 件: 1 件あたりの見逃し 0.420 見逃しの期待件数 12.60

1 回あたり 1% の見逃しでも、100 回で 63%、1000 回ではほぼ確実に見逃しが起こります。3 回で確認に戻すと、自動の審査だけで見逃す確率は約 3% に抑えられます。3 層の積 0.00050.0005 は、2%2\% の共通の原因があるだけで 0.020.02 余りに上がります。最後の 4 行は次節の例です。

人間の承認も、確率的な層の 1 つです。承認の要求が多すぎると、1 件ずつを確かめなくなります。この効果を、仮定を明示した模型で調べます。

次の命題の記号は、mm が確認を求める件数、dd がそのうちの危険な行為の件数、h(m)h(m) が危険な行為を誤って承認してしまう確率、LL が見逃しの期待件数です。確認を減らす仕組みを入れる前と後の LL を比べて、後のほうが小さくなる条件を求めるのがねらいです。式が多いときは、命題の後の「2 の不等式の読み方」の段落から読んでも構いません。

命題 5.4(承認の件数と見逃し(仮定つきの模型))✓

1 つの作業で人間に確認を求める件数を mm とし、そのうち危険な行為は dd 件とする。仮定: 人間が危険な行為 1 件を誤って承認する確率は、件数の関数 h(m)h(m) で、hh は広義単調増加(件数が増えるほど、1 件あたりの確認の質は下がるか、変わらない)である。危険な行為の見逃しの期待件数を L=d h(m)L = d\,h(m) とする。

確認を減らす仕組み(許可規則や、サンドボックスの中での自動実行)を入れて、m0m_0 件を確認なしで実行するようにし、その中に危険な行為が d0d_0 件含まれるとする。確認なしで実行された危険な行為が被害につながる確率を η\eta とする。このときの見逃しの期待件数は L′=(d−d0) h(m−m0)+d0 ηL' = (d - d_0)\,h(m - m_0) + d_0\,\eta である。

  1. d0=0d_0 = 0(確認なしにしたものに危険な行為が含まれない)ならば、L′≤LL' \le L。
  2. 一般には、L′<LL' \lt L となるのは d0 (η−h(m−m0))<d (h(m)−h(m−m0))d_0\,\bigl(\eta - h(m - m_0)\bigr) \lt d\,\bigl(h(m) - h(m - m_0)\bigr) のとき、かつそのときに限る。
証明(命題 5.4)

見逃しの件数は、危険な行為ごとの「見逃したら 11、そうでなければ 00」の和なので、期待件数は各行為の見逃しの確率の和です。仕組みを入れたあと、確認に残る危険な行為は d−d0d - d_0 件で、それぞれの見逃しの確率は h(m−m0)h(m - m_0)、確認なしで実行された危険な行為は d0d_0 件で、それぞれ確率 η\eta で被害につながります。よって L′=(d−d0) h(m−m0)+d0 ηL' = (d - d_0)\,h(m - m_0) + d_0\,\eta です。

1: d0=0d_0 = 0 のとき L′=d h(m−m0)L' = d\,h(m - m_0) です。m−m0≤mm - m_0 \le m で hh は広義単調増加なので h(m−m0)≤h(m)h(m - m_0) \le h(m)、したがって L′≤d h(m)=LL' \le d\,h(m) = L です。

2: L−L′=d h(m)−(d−d0) h(m−m0)−d0 η=d (h(m)−h(m−m0))−d0 (η−h(m−m0))L - L' = d\,h(m) - (d - d_0)\,h(m - m_0) - d_0\,\eta = d\,\bigl(h(m) - h(m - m_0)\bigr) - d_0\,\bigl(\eta - h(m - m_0)\bigr) です。L′<LL' \lt L はこの値が正であることと同値で、それは d0 (η−h(m−m0))<d (h(m)−h(m−m0))d_0\,(\eta - h(m - m_0)) \lt d\,(h(m) - h(m - m_0)) と同値です。

これは仮定に依存する命題で、経験的な主張ではありません。 hh が単調増加であること、その形、η\eta の値は、どれも模型の仮定で、公式資料にも数値はありません。命題が示すのは、仮定のもとでの条件だけです。

2 の不等式の読み方は次のとおりです。右辺は、確認の件数が減ることで、残った確認の質が上がる効果です。左辺は、確認なしにした危険な行為について、人間の確認(見逃しの確率 h(m−m0)h(m - m_0))の代わりに仕組み(被害につながる確率 η\eta)に任せることの損得です。η≤h(m−m0)\eta \le h(m - m_0)、つまり仕組みのほうが人間より見逃さないなら、左辺は 00 以下で、不等式は(hh が真に増加していれば)成り立ちます。サンドボックスの中での自動実行は、効果を決定的に囲うので、囲われる種類の被害については η=0\eta = 0 です。許可規則で「安全なコマンド」を確認なしにする場合は、d0d_0 をできるだけ 00 に近づけるような規則の選び方が要ります。

公式ドキュメントは、よく使う安全なコマンドを許可の一覧に入れられることを、確認の疲れを和らげる仕組みとして挙げています。上の出力の最後の 4 行は、h(m)=min⁡(1,0.02+0.004 m)h(m) = \min(1, 0.02 + 0.004\,m)、危険な行為の割合 0.30.3 という仮の値での LL で、件数を 5 倍(20 件から 100 件)にすると見逃しの期待件数が 21 倍(0.600.60 から 12.6012.60)になっています。件数と 1 件あたりの見逃しの両方が増えるためです。

人間を、合格・不合格を返す検証器(定義 2.2[LLMとプログラミング])と見ると、hh は偽陽性率(誤ったものを合格にする率)にあたります。採用されたものの誤り率が偽陽性率にほぼ比例するという定理(定理 7.2[LLMとプログラミング])は、もっともらしい誤り(定義 7.1[LLMとプログラミング])を見抜く側の限界を述べたものでした。ここでの結論はその延長で、承認という検証の質を保つには、承認に回す件数そのものを減らす設計が要る、ということです。

6. 拡張と、信頼しなければならない主体

Section titled “6. 拡張と、信頼しなければならない主体”

前章で、拡張の仕組みを、ループのどこに作用するかで分類しました。安全性の観点では、拡張は 2 種類のものを増やします。

命題 6.1(拡張は経路かプログラムを増やす)✓

導入した拡張の集合を XX とし、各拡張 ee の提供者を π(e)\pi(e) とする。拡張は、次の一方または両方を足すとする(前章の分類による)。

  • 信頼できない経路: その拡張が決める内容(ツールの説明と結果、スキルの本文など)が文脈に入る経路。
  • 自動で動くプログラム: 利用者の権限で、権限の関門を通らずに動くプログラム(フックのコマンド、利用者の機械の上の MCP サーバのプロセスなど)。

このとき次が成り立つ。

  1. 文脈に入る経路の集合と、自動で動くプログラムの集合は、XX について単調に増える(X⊆X′X \subseteq X' なら、XX のもとでの集合は X′X' のもとでの集合に含まれる)。
  2. 「自動で動くプログラムに敵対的なものが無い」という性質が成り立つためには、自動で動くプログラムを足す拡張の提供者をすべて信頼する必要がある。すなわち、信頼しなければならない主体の集合は {π(e):e∈X, e は自動で動くプログラムを足す}\{\pi(e) : e \in X,\ e \text{ は自動で動くプログラムを足す}\} を含む。
  3. 自動で動くプログラムは QQ の呼び出しではないので、定理 3.2 の上界の対象にならない。
証明(命題 6.1)

1: 各拡張が足す経路とプログラムは、その拡張だけで決まります。全体の集合は、導入した拡張ごとの集合の合併なので、拡張を足すと合併は大きくなるか変わらないかです。

2: 提供者 π(e)\pi(e) を信頼しないとは、定義 2.1 の定義により、π(e)\pi(e) が与えるプログラムが敵対的でないと仮定しないことです。その場合、ee が足すプログラムが敵対的である可能性が残り、性質は保証されません。対偶を取ると、性質が成り立つためには、そのような ee の提供者をすべて信頼する必要があります。

3: 定理の上界は、関門を通る呼び出し(QQ の元)についてのものです。フックのコマンドや MCP サーバのプロセスは、ハーネスが起動するプログラムで、モデルのツール呼び出しとして関門を通るものではありません。したがって定理の主張には含まれません。

この命題は定義からの帰結ですが、数え方を与えます。拡張を 1 つ足すたびに、信頼しなければならない主体が 1 つ増えるか、信頼できない経路が 1 つ増えます。前章の命題(命題 4.5[拡張の仕組み])が示した「フックは必ず実行される」という性質は、検査のためのフックでは強みですが、提供者を信頼できないフックでは、そのまま弱みになります。フックの失敗時の向き(命題 4.3[拡張の仕組み])も、同じ仕組みの両面です。

公式ドキュメントから、3 に関わる事実を挙げます(2026-10-10 確認)。

  • プラグイン(“Plugin security and trust”)。導入したプラグインは、利用者の権限で任意のコードを実行できます。権限規則とサンドボックスが覆うのはモデルのツール呼び出しで、プラグインが自分で動かすコード(フック、MCP サーバのプロセスなど)ではありません。導入の前に確認の文が表示され、そこには、プラグインに何が含まれるかを Anthropic は管理しておらず、意図どおりに動くことや変わらないことを確かめられない、とあります。自動更新が有効だと、確認したファイルが背後で変わりえます。
  • MCP サーバ(“Security”)。自分で書いた MCP サーバか、信頼する提供者のサーバを使うことが勧められています。Anthropic はコネクタを掲載の基準に照らして審査するが、MCP サーバの安全性の監査や管理はしない、と書かれています。
  • フック(“Hooks reference”)。コマンドのフックは利用者の全権限でシェルコマンドを実行する、と警告されています。
  • リポジトリの中の設定(“Configure permissions” の「What runs before you trust a folder」)。リポジトリは、設定ファイルを通じて、フックや許可規則や MCP サーバを持ち込めます。対話的なセッションでは、信頼していないフォルダで起動すると確認が出て、設定ファイルのフックは確認を受け入れるまで実行されません。プロジェクトの許可規則も確認のあとで適用されます(deny と ask の規則は、制限するだけなので確認を待ちません)。プロジェクトの .mcp.json のサーバには、別の承認があります。一方、非対話の実行(-p)と SDK のセッションは信頼の確認を出しません。公式の表によれば、そこでは、リポジトリの設定ファイルのフックは、信頼したことのないフォルダでも実行されます(プロジェクトの許可規則のほうは使われません)。自分が書いていないリポジトリで非対話の実行をする前に、プロジェクトの設定を読み込まない指定や、フックを無効にする指定を検討するよう、公式ドキュメントは勧めています。どの内容がどの場合に使われるかは表にまとめられているので、細部は出典を見てください。

ここまでの命題を、設計する側の手順として並べ直します。

  1. 能力を数える。確認なしで実行できる行為の集合 ArunA_{\mathrm{run}} を書き出す。それが最悪の場合の上界である(定理 3.2)。
  2. 3 つの条件を調べる。(a) 非公開の情報を読めるか、(b) 信頼できない入力が入るか、(c) 外部へ送れるか。3 つがそろう構成では、どれか 1 つを閉じる(命題 4.2)。
  3. 決定的な層で閉じる。閉じるときは、モデルの判断に頼らない層を使う。deny 規則、サンドボックス、ブロックするフック(命題 4.4、命題 5.2 の 3)。その層の対象の範囲を確かめる。
  4. 確率的な層は試行の回数とともに考える。分類器や検査は、見逃しの確率と、試される回数の両方で評価する(命題 5.3)。
  5. 人間の承認を薄めない。承認に回す件数を、決定的な層で減らす(命題 5.4)。
  6. 拡張の提供者を数える。導入した拡張ごとに、何を足したか(経路か、プログラムか)と、誰を信頼したことになるかを書き出す(命題 6.1)。

公式ドキュメントが、信頼できない内容を扱うときの勧めとして挙げているのは、提案されたコマンドを承認の前に確かめる、信頼できない内容を直接パイプで渡さない、重要なファイルへの変更を確かめる、外部のサービスとやり取りするときは仮想マシンを使う、不審な振る舞いを報告する、の 5 つです。脆弱性を見つけた場合の報告の窓口があること(公開せずに報告すること)も書かれています。

読み取り専用の調査の構成を Agent SDK で書くと、公式ドキュメントの書式では次の形です。読み取りの 3 つのツールだけを事前に許可し、権限モードを、確認が要る呼び出しをすべて拒否するもの(dontAsk)にします。ただし公式ドキュメント(“Configure permissions” の Agent SDK 版)によれば、dontAsk でも、既定のモードで確認の要らない呼び出し(読み取り専用とみなされる組み込みのシェルコマンド、サブエージェントを起動するツール、作業ディレクトリの中のファイルの読み取りなど)は、一覧に入れていなくても実行されます。ツールをモデルの手の届かないところに置くには、拒否の一覧(disallowed_tools)に名前を書く、とあります。そこで、シェル・ウェブ・サブエージェントのツールを拒否の一覧に入れます。また、SDK は既定で利用者・プロジェクトの設定ファイルを読み込み、信頼の確認を出さないので(6 節)、自分が書いていないリポジトリを対象にするときは setting_sources=[] で設定ファイルを読み込まないようにします(公式のリファレンスによれば、Python SDK 0.1.59 以前は空のリストを省略と同じに扱うので、この指定が効くのはそれより新しい版です。組織の管理設定はこの指定に関係なく読み込まれます)。このコードは、この記事では実行していません(API を呼ぶため。出力も載せません)。API キーは環境変数から読まれます。

# 未実行。Agent SDK の公式ドキュメントの書式(2026-10 時点)に合わせた最小の形。
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
options = ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob"], # この 3 つは確認なしで実行
permission_mode="dontAsk", # 確認が要る呼び出しは拒否する
disallowed_tools=["Bash", "WebFetch", "WebSearch", "Agent"], # 文脈から取り除く
setting_sources=[], # リポジトリの設定ファイル(フックなど)を読み込まない
max_turns=20,
)
async for message in query(prompt="このリポジトリの構成を要約して", options=options):
if isinstance(message, ResultMessage):
print(message.subtype)
asyncio.run(main())

この構成は 4.2 節の構成 1 にあたります。許可したツールと拒否したツールの一覧が上のとおりに働き、ほかに (c) にあたるツール(MCP サーバのツールなど)が接続されていなければ、(c) が無いので、模型の上では流出の経路はありません。実物で使えるツールの全体は版と環境で変わるので、公式のツールの一覧と照らして確かめてください。それでも、読んだファイルの内容が最終の応答に影響することは防げないので、応答を使う側での確認は要ります。

この章の命題は、どれも「囲う」ことについてのものでした。モデルが外から入った内容に操作されないようにすることは、モデルを作る側の仕事で、公式資料もそのための取り組みを述べています。しかしそれは確率的な層の 1 つです。利用する側が自分で決められるのは、能力の集合と、決定的な層の置き方です。

演習 8.1易

ある構成で、確認なしで実行できる行為が「作業ディレクトリのファイルの読み取り」「作業ディレクトリのファイルの編集」「npm test の実行(サンドボックスなし)」の 3 種類だけだとする。定義 4.1 の (a)・(b)・(c) のそれぞれが開いているかを、理由とともに答えよ。

解答

(a) 開いています。作業ディレクトリに非公開の情報(未公開のコード、設定ファイルの中の値)があれば、読み取りでそれが文脈に入ります。(b) 開いています。作業ディレクトリのファイルや、テストが出力する内容は、利用者以外が書いたものを含みえます。(c) 開いていると見るべきです。npm test はテストのコードを実行し、テストのコードは編集できるので、サンドボックスなしではネットワークへの接続を含む任意の処理ができます。権限規則が見ているのは npm test という文字列だけで、その効果ではありません(注意 3.3)。3 つがそろうので、命題 4.2 の 1 により経路があります。サンドボックスを有効にして許可ドメインを空にし、許可ドメインの外への接続があとから許されない設定(4.3 節)にすれば、命題 4.4 によりシェルコマンドの (c) が閉じます。

演習 8.2標準

審査の見逃しの確率を ε=0.002\varepsilon = 0.002 とする(仮の値)。(1) 独立な試行で、少なくとも 1 回見逃す確率が 1/21/2 を超える最小の nn を求めよ。(2) 3 回止めたら人間の確認に回す規則のもとで、確認に回る前に見逃す確率を求めよ。

解答

(1) 1−(1−0.002)n>1/21 - (1 - 0.002)^n \gt 1/2 は 0.998n<1/20.998^n \lt 1/2、すなわち n>ln⁡2/(−ln⁡0.998)n \gt \ln 2 / (-\ln 0.998) です。−ln⁡0.998≈0.002002-\ln 0.998 \approx 0.002002 なので n>0.6931/0.002002≈346.2n \gt 0.6931 / 0.002002 \approx 346.2、最小の nn は 347347 です。(2) 命題 5.3 の 2 により 1−0.9983=1−0.994012≈0.0059881 - 0.998^3 = 1 - 0.994012 \approx 0.005988、約 0.6%0.6\% です。3ε=0.0063\varepsilon = 0.006 とほぼ一致します。

演習 8.3標準

見逃しの確率がどちらも 0.050.05 の 2 つの層がある。(1) 独立な場合に両方を通り抜ける確率を求めよ。(2) 確率 0.030.03 で両方が同時に見逃す共通の原因があり、それ以外では独立に 0.050.05 で見逃すとき、通り抜ける確率を求めよ。(3) (2) の状況で、同じ種類の層をもう 1 つ足すのと、共通の原因を半分(0.0150.015)にするのとでは、どちらが確率を下げるか。

解答

(1) 0.052=0.00250.05^2 = 0.0025。(2) 命題 5.2 の 2 により 0.03+0.97×0.0025=0.0324250.03 + 0.97 \times 0.0025 = 0.032425。(3) 層を足す(3 層、共通の原因は 0.030.03 のまま)と 0.03+0.97×0.000125=0.030120.03 + 0.97 \times 0.000125 = 0.03012。共通の原因を半分にする(2 層)と 0.015+0.985×0.0025=0.017460.015 + 0.985 \times 0.0025 = 0.01746。共通の原因を減らすほうが大きく下がります。層を足しても q=0.03q = 0.03 より下には行きません。

演習 8.4易

ある利用者が、(i) 第三者のマーケットプレイスからプラグインを 1 つ(フック 1 つと stdio の MCP サーバ 1 つを含む)、(ii) 自分で書いたスキルを 1 つ、(iii) 遠隔の MCP サーバ(課題管理のサービス)を 1 つ導入した。命題 6.1 に沿って、増えた「自動で動くプログラム」と「信頼できない経路」を数え、新たに信頼したことになる主体を挙げよ。

解答

自動で動くプログラム: (i) のフックのコマンドと、(i) の MCP サーバのプロセスの 2 つ(どちらも利用者の機械の上で、利用者の権限で動く)。(iii) は遠隔なので、利用者の機械の上では動きません。信頼できない経路: (i) の MCP サーバのツールの説明と結果、(iii) のツールの説明と結果(課題管理の書き込みは、サービスの利用者なら誰でも書きうるので、外部の内容の作者も含む)の 2 つ。(ii) のスキルは自分で書いたものなので、信頼できる経路です。新たに信頼したことになる主体は、(i) のプラグインの作者(プログラムを足すので、敵対的でないと仮定している)と、プラグインを配るマーケットプレイスの管理者(自動更新が有効なら、内容を変えうる)です。(iii) の提供者については、応答を信頼できない経路として扱う限り、プログラムの意味での信頼は要りませんが、(c) にあたる送信先として、何を送るかを権限規則で決める必要があります。

いずれも公式の一次資料で、確認日は 2026-10-10 です。保護の仕組みと既定値は版で変わるので、設計に使うときは該当のページで確かめてください。

このテーマの 100 本ノック(40 問)

執筆: Claude Code(Opus 5.5)、Claude Code(Sonnet 5.5)・監査 3 回(Claude Code)・最終 2026-10-12

この記事の誤りを報告する ・運営: 夢現技研合同会社 ・料金 ・利用条件 ・特定商取引法に基づく表記

© 2026 夢現技研合同会社 ・コード例は MIT ライセンスです。