4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

プロンプトインジェクションの「その後」を設計する — エージェントフレームワークの信頼境界

4
Posted at

はじめに

プロンプトインジェクションの記事はこの1年でずいぶん増えました。しかし、ほとんどが「どうやって注入を検知・ブロックするか」という入口の話で終わっています。

本記事ではそこから一歩踏み込んでCheck Point の Black Hat 報告記事/The Register の取材記事/Check Point Research の技術記事を調査し、そこから引ける「自分の構成の棚卸し観点」までをまとめました。

筆者は Claude Code / Cowork でのエージェント運用を日常的に組んでおり、メモリ永続化やチェックポイント、スキルの動的ロードといった機構を自分の手で回しています。そんな筆者がこの調査を読んで一番刺さったのは、報告された脆弱性のほとんどがモデルの問題ではなくモデルの周りの配管の問題だった点でした。

背景:議論が「入口」に偏っていた

LLM は system prompt / user query / ツールが取得したコンテンツを単一のトークン列として処理します。そのため、それらの間に権限境界を強制する信頼できる仕組みが存在しません。これによるプロンプトインジェクションのリスクは OWASP の LLM 向けリスク整理でも繰り返されています。

ここまでは多くの人が知っていますが、問題は次にあります。「防げないなら、防げなかったときに何が起きるのかを実装者としてどこまで具体的に把握しているか」です。

Check Point の Shahar Tal 氏と Yarden Porat 氏は、この「注入後(post-injection)」を1年かけて掘りました。Porat 氏は The Register にこう述べています。

“Our research shows a deeper failure: in many agentic frameworks, prompt-controlled content can cross the boundary into trusted framework logic itself,”

(訳意:多くのエージェントフレームワークでは、プロンプト経由で攻撃者が制御できるコンテンツが、フレームワーク自身の信頼された論理の内側にまで越境してしまう。)

つまり、攻撃者が仕込んだ文字列が「モデルを騙す」だけでは終わらずオーケストレーション、メモリ、状態、ルーティング、システム命令といった本来ユーザー入力が触れてはいけない層に到達しうる、ということです。

何が報告されたのか

対象フレームワークと件数

The Register の記事では、対象として LangChain、LangGraph、CrewAI、AutoGen、Microsoft Agent Framework、Google ADK が挙げられ、11件の脆弱性を発見・開示したと書かれています。

一方、Check Point 自身の Black Hat 振り返り記事では、監査対象を LangChain / Google ADK / Microsoft Agent Framework / CrewAI の4つとし、12件の CVE を発見したと書かれています。

この2つは件数もフレームワークの列挙も一致していません。さらに、後述するとおり Microsoft の案件には CVE が発番されていないと The Register は書いており、「12 CVEs」という表現とも整合しません。筆者はこの食い違いを解消できていないので、どちらか一方を正として引用するのは避けます。実務上重要なのは件数ではなく、後述するバグクラスの共通性のほうです。

ケース1: Microsoft Agent Framework のチェックポイント

エージェントには、状態を保存して後から巻き戻すための checkpoint という機構があります。会話履歴などを永続ストレージにシリアライズしておき、エラー時にゼロからやり直す代わりに保存済み状態を読み直すという仕組みです。

Check Point が見つけたのは checkpoint データのデシリアライズが安全でないというものでした。攻撃の流れは Tal 氏の説明が明快です。

“One person's message plants the payload, and then a different person rewinds their own session, which triggers the payload, and now the attacker has a shell on that server,”

(訳意:ある人物のメッセージがペイロードを仕込み、別の人物が自分のセッションを巻き戻すとペイロードが発火し、攻撃者はそのサーバー上のシェルを得る。)

ここで注目したいのは、危険なツールを1つも呼んでいないことです。エージェントは文書を読んだだけ。発火させたのは、フレームワーク自身の「保存してリロードする」という正常動作です。

The Register によると、Microsoft はこの報告を認め、10,000 ドルのバグバウンティを支払って修正しています。ただし発見時点でフレームワークが一般提供(GA)製品ではなかったため、CVE は発番されていません。修正としては、Agent Framework のハードニングに加え、該当の checkpoint ファイルにセキュリティ境界を定義する記述が追加された旨が Microsoft のコメントとして紹介されています。

CVE が出ないということは、依存関係スキャナには何も映らないということでもあります。GA 前のフレームワークを本番に近い場所で使っている場合、この非対称性は覚えておく価値があります。

ケース2: Google ADK の開発用アシスタント

もう1つが Google ADK(Agent Development Kit)です。Porat 氏の説明はこうです。

“ADK ships a built-in development assistant that can write files, and it stays reachable over the HTTP API even though it is hidden from the app listing,”

(訳意:ADK にはファイルを書ける開発用アシスタントが同梱されており、アプリ一覧からは隠されているにもかかわらず HTTP API 経由で到達可能なままになっている。)

攻撃手順として紹介されているのは、セッションを開き、import 時に Python コードが走るエージェントを書かせ、そのエージェントの実行をサーバーに依頼する、というものです。サーバーがファイルを import した時点で攻撃者のコードが動きます。

そこから環境の API キーとコンテナの Google Cloud サービスアカウントに手が届く、と Porat 氏は述べています。Google の対応は Microsoft と対照的でした。当初はバグと認めず、最終的に 3,133.70 ドルのバウンティと部分的な修正にとどまった、と The Register は伝えています。なお、Google は The Register の問い合わせに応答していない、とも書かれています。

「開発用の便利機能が、デプロイコマンド経由でそのまま本番に出ていく」というのは、エージェント特有の話ではなく古典的な設定ミスの形です。ただ、エージェントフレームワークは開発体験を良くするための機能が非常に多いぶん、この地雷の密度が高くなります。

ケース3: Cloudflare Code Mode — サンドボックスではなく「糊」が境界

同じ2人が Black Hat のもう1つの枠で発表したのが、Cloudflare の Code Mode に関する調査です。Code Mode は「モデルにツールを1つずつ呼ばせる代わりに、小さなプログラムを書かせてサンドボックス内で実行する」というアプローチを取ります。筆者から見ても筋の良い賭けだと思っていました。

Check Point の報告によれば、彼らはモデルではなくランタイム側、つまり Workers を動かす workerd を直接狙い、**5件のメモリ破壊系脆弱性(うち2件が Critical)**を発見しています。代表例として挙げられているのが次の2つです。

  • URLPattern の欠陥:テナントを隔てるはずの境界を越えて、共有メモリから隣のテナントのシークレットを読み出せた。防御機構をすべて有効にした状態で成立したと書かれています。
  • node:zlib の use-after-free:プロンプトインジェクションを起点に、任意メモリの読み書きへ、そこからサンドボックス脱出まで連鎖させた。

Cloudflare は通常の脆弱性開示プロセスを経て修正を出し、セルフホスト向けには workerd v1.20260619.1 で塞がれた、とされています。Check Point Research 側の記事によれば、記事執筆時点(2026年8月)で CVE は割り当てられていないとのことです。セルフホストで Code Mode 相当を動かしている場合はバージョンの確認が要ります。

Check Point のまとめ記事にある次の一文が、個人的には今回いちばん持ち帰りたかった部分です。

The sandbox protects the engine, not the glue holding it together.

(訳意:サンドボックスが守るのはエンジンであって、それを繋いでいる糊ではない。)

その直後は、こう続きます。

Once a model is the one writing the code, that glue becomes the boundary, and it needs to be audited like one.

(訳意:モデルがコードを書く側に回った瞬間、その糊が境界になる。そして糊は、境界として監査されなければならない。)

共通の構造:データ平面から制御平面への越境

3つのケースを並べると、形は同じです。攻撃者が触れるのは「データ」のはずだった経路なのに、そのデータが制御側の判断材料になっている。

意図された経路は「制御平面がデータ平面を読む」だけのはずです。ところが実装上は、

  • データがシリアライズされ、後で復元される(=コードとして解釈されうる)
  • データがファイルパスやURLとしてそのまま使われる(=パストラバーサル、SSRF)
  • データがパーサに食わせられる(=メモリ破壊)

という形で読み取りが実行に化けます。プロンプトインジェクション対策の議論がモデル層に集中している間に、この化け方のレビューが手薄になったというのが今回の指摘のようです。

自分の構成でチェックしたい4つの観点

ここからは、公開情報を自分の環境に引き当てたときのチェック観点です。筆者が実際に自分の構成を見直した際に使った順序で書きます。

1. 永続化されるものを全部数える

エージェント運用では、思っている以上に多くのものがディスクに落ちます。会話履歴、メモリファイル、チェックポイント、compaction 後の要約、タスク状態、キャッシュ。

問うべきは1つです。「これを読み戻すとき、コードが動く経路はあるか」

# 危険な形(概念コード。実在の実装ではありません)
import pickle

def load_checkpoint(path: str):
    with open(path, "rb") as f:
        return pickle.load(f)  # 任意コード実行に直結しうる
# 安全側に寄せた形(概念コード。Python 3.9 以降を想定)
import json
from typing import Any

ALLOWED_KEYS = {"messages", "step", "scratchpad"}

def load_checkpoint(path: str) -> dict[str, Any]:
    with open(path, "r", encoding="utf-8") as f:
        data = json.load(f)          # コード実行経路のない形式に限定
    if not isinstance(data, dict):
        raise ValueError("checkpoint must be an object")
    return {k: v for k, v in data.items() if k in ALLOWED_KEYS}

ポイントは「JSON にすれば安全」ではなく、復元時にオブジェクトの型やコールバックを外部データに決めさせないことです。スキーマを固定し、許可したキーだけを通す。Microsoft のケースが示したのは、この一手間が抜けると「他人が仕込んで自分が発火させる」という時間差攻撃が成立する、ということでした。

2. コード生成 → 実行の経路を数える

Code Mode 系のアプローチ、exec を含むツール、動的 import、プラグイン/スキルのロード。モデルの出力が実行可能な形になる箇所は、すべて境界です。

サンドボックスの有無だけでなく、サンドボックスの外側にある薄い層(引数の受け渡し、ファイルの配置、圧縮・展開、URL のパース)を見ます。Cloudflare のケースで壊れたのはまさにそこでした。

3. 開発用エンドポイントの到達性を確認する

「アプリ一覧から隠れている」ことと「到達できない」ことは別だ、というのが ADK のケースの教訓です。確認すべきは3つ。

  1. その API はデフォルトで認証があるか
  2. デプロイ用コマンドは何を公開するか(意図しないパスまで出ていないか)
  3. 到達できた場合、そこから何のクレデンシャルに手が届くか

3つ目が実は一番重要です。Porat 氏らが Google を説得できたのも、「開発者にとって不便」ではなく「シークレット窃取に至る」と結果で議論したからだ、と記事には書かれています。脆弱性報告に限らず、社内で優先度を上げてもらうときにも使える組み立てだと思いました。

4. パーサに何を食わせているかを追う

エージェントは PDF、HTML、画像、圧縮ファイル、Office 文書といった多様な入力をパースします。ネイティブ実装のパーサに未検証の外部データを流すのは、20年前から変わらず危険です。エージェント文脈では、その「外部データ」が攻撃者が置いた文書でありうる点だけが新しい。

まとめ

  • プロンプトインジェクション対策の議論は入口に偏っていた。今回の調査は「注入は起きる前提で、その後にフレームワークが何をするか」を見ろと主張している。
  • 報告されたバグクラスは insecure deserialization / SSRF / path traversal / use-after-free と、いずれも古典的なもの。新しいのはバグクラスではなく、それが座っている層。
  • 具体例として、Microsoft Agent Framework のチェックポイント復元による RCE、Google ADK の無認証な開発用 API、Cloudflare workerd のメモリ破壊が挙げられている。
  • 共通構造は「データ平面から制御平面への越境」。永続化・コード実行経路・開発用エンドポイント・パーサの4点を自分の構成で数え直すのが、今日できる一手。
  • 件数(11 か 12 か)や CVE の有無には出典間の食い違いがある。本記事はそれを解消していない。

エージェントの層は、守り方が固まるより速く積み上がっています。せめて、自分が積んだ分については、どこが境界なのかを言えるようにしておきたいところです。

参考

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?