AI駆動のアシスタントは、指示の約99%に従いますが、残りの1%こそが攻撃者が付け入る隙となります。巧妙に作られたプロンプトを入力することで、悪意のあるユーザーはモデルに本来呼び出すべきではない関数を実行させ、データを盗んだり、権限が必要なアクションを実行させたりすることができます。解決策は、より丁寧な言い回しにすることではありません。この欠陥を認可(authorization)の問題として扱い、危険なツールをモデルの手に届かないようにすることです。

なぜプロンプトインジェクションは単なる言い回しの問題ではないのか

開発者は、大文字の警告や番号付きのルール、「管理者関数を呼び出さないこと」といった条項によってエージェントを強化しようとしがちです。これらの防御策は、モデルが「Xをしてはいけない」という一文に従うことを前提としています。実際には、リクエストの言い換え、異なるペルソナのロールプレイ、あるいは単に余計なコンテキストを追加することによって、モデルを誘導して指示を無視させることが可能です。言語による境界は交渉の余地がありますが、攻撃者のプロンプトには制限がなく、テストにかかるコストもゼロです。

真の脆弱性は、エージェントが受け取るツールリストにあります。プロンプトのスキーマに管理者権限を付与する関数が含まれている場合、モデルはその権限へのマップ(地図)を手にしたことになります。たとえプロンプトに「顧客に対しては使用しないでください」と書かれていても、その関数が実行環境に存在するため、モデルは呼び出すよう説得されてしまう可能性があります。したがって、問題は認可のギャップにあります。つまり、システムが、それを使用する権利のない呼び出し手に対して、特権的な機能を公開してしまっているのです。

露出を制限することでエージェントを保護する

このギャップを埋める最も簡単な方法は、モデルに対して、使用を許可されていないツールへのアクセスを与えないことです。ツールリストをAPIキーだと考えてください。キーが存在しなければ、呼び出しは発生しません。現在のコンテキストに存在しない関数を、どんなに巧妙な言い回しを使っても呼び出すことはできません。

間違った方法

Prompt: “You are an assistant. Do not use the adminDeleteUser function for regular customers.”

モデルは依然としてツールボックスの中に adminDeleteUser を見ており、それを呼び出すよう騙される可能性があります。

正しい方法

Prompt schema for a regular customer: { “functions”: [ “searchCatalog”, “placeOrder” ] }

adminDeleteUser は決して現れないため、モデルがそれを呼び出す経路はありません。

開発者のための3つの実践的なルール

  1. リクエストごとにツールリストを構築する – 認証された呼び出し手の権限に基づいて、関数カタログを動的に生成します。顧客には必要な関数のみが表示され、管理者はすべてのセットが表示されます。
  2. フェイルクローズ(Fail closed) – ユーザーの身元が確認できない場合は、汎用的な「すべてのツールが利用可能」というフォールバックではなく、空のリストを返します。これにより、未認証のリクエストが予期せぬ権限を得ることを確実に防げます。
  3. 共有状態を避ける – ツールの定義をキャッシュする際、ユーザー固有のデータを共有オブジェクトに書き込まないでください。Copy-on-write(コピーオンライト)やセッションごとのコピーを使用し、あるユーザーの権限が別のユーザーのリクエストに漏れ出さないようにします。

もし一般ユーザーに提示されるスキーマが管理者に表示されるものと同一であれば、セキュリティ境界は依然としてプロンプトのテキストであり、プロンプトは信頼できるセキュリティメカニズムではありません。

何が私たちをここまで導いたのか

プロンプトインジェクションは、開発者が大規模言語モデル(LLM)を、外部APIの呼び出し、コードの実行、またはデータベースの変更を必要とする本番ワークフローに組み込み始めたときに表面化しました。モデルの「推論」は、利用可能なツールのリストを含むプロンプトによって導かれます。初期のプロトタイプでは、モデルが「管理者以外についてはレコードを削除しないでください」といった自然言語のルールに従うことを前提としていました。攻撃者は、数行の文章を追加するだけでそれらのルールを回避し、モデルに同じ削除関数を呼び出させることができることをすぐに証明しました。

コミュニティの最初の反応は、プロンプトの言語を厳格にしたり、「決してXをしないでください」という条項を追加したり、疑わしいトークンを削除する正規表現フィルタを組み込んだりすることでした。これらの対策は、偶発的な誤用は減らしましたが、リクエストを言い換えるだけで済む、意志を持った攻撃者を止めることはできませんでした。根本的な原因である「信頼できない呼び出し手に特権関数を公開していること」は、解消されないままでした。

誰が勝ち、誰が負けるのか

リクエストごとのツールスコープを採用する企業は、明確で強制可能な境界を獲得します。彼らのエージェントは、たった一つの不正なプロンプトが管理者権限を解放してしまうことを恐れることなく、大規模に展開できます。コンプライアンスチームも監査証跡を高く評価します。モデルに送信された関数のリストは、ログに記録してレビューできる具体的なアーティファクトとなります。

プロンプトのみのガードに頼る開発者は、常に変化し続ける標的に直面し続けます。彼らのエージェントはテストでは機能しているように見えても、実環境では侵害される可能性があり、データ漏洩、不正な取引、またはコンプライアンス違反につながる恐れがあります。侵害が発生した際のコストは、動的なツールリストを構築する労力をはるかに上回ります。

反論:「より優れたプロンプトがあれば十分である」

十分なインストラクション・エンジニアリング(階層化されたプロンプト、システムメッセージ、人間からのフィードバックによる強化学習など)を行えば、モデルに「〜してはいけない」という条項を遵守させることができると主張する者もいます。しかし現実は、言語モデルは確率的な生成器であり、厳格なセキュリティルールではなく、最も可能性の高い継続内容を重み付けしているに過ぎません。微調整されたガードレールがあったとしても、新しい言い回しによって制限を突破される可能性があります。特に、攻撃者がコストをかけずに際限なく試行錯誤できる場合にはなおさらです。ガードレールはノイズを減らすためには有用ですが、それだけを唯一の防御策としてはいけません。

次に注目すべき点

  • ツール・スコーピングをファーストクラスのAPIとして公開するフレームワーク – ユーザーごとの権限を宣言し、プロンプトが構築される前に自動的に関数リストを削減できる新しいライブラリが登場することが予想されます。
  • 標準化された「関数マニフェスト」 – 業界団体が、公開関数と特権関数を分離するJSONスキーマを定義し、リクエスト固有のマニフェストを生成しやすくする可能性があります。
  • ランタイムでの強制適用 – 一部のプラットフォームでは、呼び出し側のトークンと呼び出される関数を照合するサンドボックス化された実行を試行しており、プロンプト・スコーピングを超えた二層目の防御を追加しようとしています。

結論は明確です。プロンプト・インジェクションを認可の欠陥として扱うべきです。モデルのツールボックスから権限のないツールを取り除くことで、巧妙に言葉を操ったプロンプトが突こうとする攻撃対象領域(アタックサーフェス)を排除できます。プロンプトは振る舞いを誘導することはできますが、適切なアクセス制御の代わりにはなりません。