detecting-indirect-prompt-injection について
LLM エージェントが外部データを取り込む前に、間接的なプロンプトインジェクションを検出するセキュリティスキルです。隠しテキストの抽出、正規化、ルールとモデルによるスキャン、対応判断を組み合わせます。
主な機能
- 01Web ページ、PDF、画像から隠しテキストを抽出
- 02難読化コンテンツの正規化とデコード
- 03ルールと分類モデルを組み合わせたスキャン
- 04ブロック、サニタイズ、許可の判定
- 05構造化された検出テレメトリーの出力
活用シーン
- 01エージェント取り込み前の外部コンテンツ確認
- 02文書や画像に含まれる隠し指示の検査
- 03レッドチーム演習でのインジェクション対策検証
- 04エージェントの予期しない動作の調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill detecting-indirect-prompt-injectionインストール後、Claude Code で/detecting-indirect-prompt-injectionを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSEreferences/api-reference.mdstandards.mdscripts/agent.py詳細
間接プロンプトインジェクションの検出
許可された用途に限る旨の通知: このスキルのスクリプトは、信頼できないコンテンツをスキャンしてインジェクションペイロードを検出し、検出モデルを実行します。スキャンは、処理を許可されているデータに対してのみ実行してください。また、抽出されたペイロードは、実行可能な信頼できない入力として扱い、特権を持つ LLM コンテキストに決して貼り付けないでください。
概要
間接プロンプトインジェクション(MITRE ATLAS AML.T0051.001、OWASP LLM01:2025)とは、LLM を利用するエージェントが外部コンテンツ(閲覧する Web ページ、要約する PDF やメール、OCR を実行する画像、読み取るツールの結果など)を取り込み、そのコンテンツに含まれる隠された指示を、開発者やユーザーからの指示であるかのようにモデルが実行してしまうことです。エージェントはコンテキストウィンドウ内のすべてのトークンを同等に権威あるものとして扱うため、読み込まれるデータを何らかの形で制御できる攻撃者は、エージェントの挙動を乗っ取ることができます。たとえば、会話履歴を流出させたり、ツール呼び出しをリダイレクトしたり、秘密情報を漏えいさせたり、接続されたシステムを経由して侵入を広げたりできます。
ユーザーが攻撃を入力する直接的なインジェクションとは異なり、間接インジェクションは信頼できそうなデータチャネルを通じて届くため、単純な入力フィルタリングでは見逃されます。ペイロードはさまざまな形で隠されています。Web ページの HTML コメントや display:none/幅ゼロのテキスト、PDF の白地に白文字や極小フォントのテキスト、画像の代替テキストや EXIF メタデータ、ピクセルに描画されたテキスト(OCR をあまり使わないフィルターでは見えなくても、マルチモーダルモデルには読み取られるもの)、Unicode のタグ/ゼロ幅文字、Base64/ROT13 による難読化などです。このスキルでは、モデルに届く前にすべてのデータを正規化してスキャンする検出パイプラインを構築します。ヒューリスティック/正規表現による検出、専用の検出モデル(Meta Prompt Guard 2、LLM Guard 経由の ProtectAI の deberta-v3 prompt-injection 分類器)、画像向けのマルチモーダル抽出を組み合わせ、さらに対応アクションと検出テレメトリを定義します。
使用する場面
- Web を閲覧したり、メールを読んだり、ドキュメントを要約したり、ユーザーがアップロードしたファイル/画像を処理したりするエージェントを構築または強化する場合。
- サードパーティのデータを取り込む LLM の前段に、コンテンツのサニタイズゲートが必要な場合。
- 取得したデータに含まれるインジェクション命令が検出されることを検証する、AI のレッドチーム/ブルーチーム演習を実施する場合。
- エージェントが、自分の作成したものではない指示を受け取ったかのように動作したインシデントを調査する場合。
- ナレッジベースに追加するドキュメントを、CI/CD で取り込み前にスキャンする場合。
前提条件
- Python 3.10 以降と仮想環境。
- 検出ツールをインストールします。
python -m venv .venv && source .venv/bin/activate
# LLM Guard — input/output scanners incl. PromptInjection
pip install llm-guard
# Hugging Face transformers for Prompt Guard 2 / deberta classifiers
pip install transformers torch
# Content extraction: HTML, PDF, images
pip install beautifulsoup4 pypdf pillow pytesseract
# pytesseract requires the Tesseract OCR engine:
# Debian/Ubuntu: sudo apt-get install -y tesseract-ocr
# macOS: brew install tesseract
# Windows: choco install tesseract
- Hugging Face の
meta-llama/Llama-Prompt-Guard-2-86Mへのアクセス(承認制)、またはオープンなprotectai/deberta-v3-base-prompt-injection-v2分類器を使用します。
目標
- Web ページ、PDF、画像から、人には見えないテキストや難読化されたテキストを抽出します。
- スキャン前にコンテンツを正規化します(ゼロ幅文字の除去、Base64/ROT13 のデコード、Unicode の平坦化)。
- ヒューリスティックおよび ML ベースのインジェクション検出器(LLM Guard PromptInjection スキャナー、Prompt Guard 2)を実行します。
- 各データのスコアを算出し、モデルへの取り込み前にブロック/サニタイズ/許可を決定します。
- SIEM に適した構造化検出テレメトリを出力し、検出結果を ATLAS AML.T0051.001 に対応付けます。
MITRE ATT&CK との対応付け
| ID | 正式名称 | 関連性 |
|---|---|---|
| AML.T0051.001 | LLM Prompt Injection: Indirect | このスキルが検出・緩和する対象の手法そのものです |
| AML.T0051 | LLM Prompt Injection | あらゆるプロンプトインジェクションの亜種を含む親手法です |
| AML.T0057 | LLM Data Leakage | 間接インジェクションの一般的な目的であり、この検出によって防止できます |
| AML.T0053 | LLM Plugin Compromise | インジェクション命令は、エージェントのツール/プラグインを標的にすることがよくあります |
ワークフロー
1. Web コンテンツから隠しテキストを抽出する
人には見えなくてもモデルには見えるコメント、非表示要素、メタデータを取得します。
# extract_html.py
from bs4 import BeautifulSoup, Comment
def extract_hidden(html: str):
soup = BeautifulSoup(html, "html.parser")
hidden = []
for c in soup.find_all(string=lambda t: isinstance(t, Comment)):
hidden.append(("comment", c.strip()))
for el in soup.select('[style*="display:none"],[style*="visibility:hidden"],[hidden]'):
hidden.append(("css-hidden", el.get_text(strip=True)))
for img in soup.find_all("img"):
if img.get("alt"):
hidden.append(("alt-text", img["alt"]))
return [h for h in hidden if h[1]]
2. 正規化して難読化を解除する
ゼロ幅文字や Unicode タグ文字を除去し、一般的なエンコーディングをデコードして、検出器が実際のペイロードを認識できるようにします。
# normalize.py
import base64, codecs, re, unicodedata
ZERO_WIDTH = dict.fromkeys(map(ord, ""), None)
TAG_RANGE = range(0xE0000, 0xE0080) # Unicode tag chars used to smuggle text
def normalize(text: str) -> str:
text = text.translate(ZERO_WIDTH)
text = "".join(ch for ch in text if ord(ch) not in TAG_RANGE)
text = unicodedata.normalize("NFKC", text)
for token in re.findall(r"[A-Za-z0-9+/=]{20,}", text):
try:
decoded = base64.b64decode(token).decode("utf-8", "ignore")
if decoded.isprintable():
text += f"\n[decoded-b64] {decoded}"
except Exception:
pass
text += "\n[decoded-rot13] " + codecs.decode(text, "rot_13")
return text
3. LLM Guard の PromptInjection スキャナーでスキャンする
LLM Guard はトランスフォーマー分類器をラップし、各入力に対するリスクスコアを返します。
# scan_llmguard.py
from llm_guard.input_scanners import PromptInjection
from llm_guard.input_scanners.prompt_injection import MatchType
scanner = PromptInjection(threshold=0.5, match_type=MatchType.FULL)
def scan(text: str):
sanitized, is_valid, risk = scanner.scan(text)
return {"is_valid": is_valid, "risk": risk} # is_valid=False => injection detected
4. 専用の検出モデル(Prompt Guard 2 / deberta)を追加する
Meta Prompt Guard 2(またはオープンソースの ProtectAI deberta 分類器)を実行し、セカンドオピニオンを取得します。
# detector_model.py
from transformers import pipeline
# Open classifier (no gating); swap to meta-llama/Llama-Prompt-Guard-2-86M if licensed
clf = pipeline("text-classification",
model="protectai/deberta-v3-base-prompt-injection-v2")
def is_injection(text: str, threshold: float = 0.5) -> bool:
out = clf(text[:512])[0]
return out["label"].upper() == "INJECTION" and out["score"] >= threshold
5. 画像内に描画されたテキストを抽出してスキャンする
マルチモーダルエージェントはピクセル内に描かれたテキストを読み取るため、OCR でテキストを認識し、同じスキャナーで実行します。
# scan_image.py
from PIL import Image
import pytesseract
def ocr(path: str) -> str:
return pytesseract.image_to_string(Image.open(path))
# Feed ocr(path) through normalize() + scan() + is_injection()
6. 判定を適用し、テレメトリーを出力する
シグナルを組み合わせてブロック/サニタイズ/許可を判定し、SIEM 向けに構造化イベントを記録します。
# decide.py
import json, hashlib
from datetime import datetime, timezone
def decide(source, raw, normalized, llmguard_invalid, model_flag):
flagged = llmguard_invalid or model_flag
event = {
"ts": datetime.now(timezone.utc).isoformat(),
"source": source,
"sha256": hashlib.sha256(raw.encode("utf-8", "ignore")).hexdigest(),
"atlas": "AML.T0051.001",
"llmguard_injection": llmguard_invalid,
"model_injection": model_flag,
"decision": "block" if flagged else "allow",
}
print(json.dumps(event))
return event["decision"]
7. コーパスで検証し、しきい値を調整する
ラベル付きのクリーンなアーティファクトとインジェクション済みアーティファクトのセットに対してパイプラインを実行し、適合率/再現率を測定して、誤検知とインジェクションの見逃しのバランスが取れるように threshold を調整します。エージェントのモデルまたは取り込み元が変わるたびに再テストしてください。
ツールとリソース
| ツール | 目的 | ソース |
|---|---|---|
| LLM Guard | PromptInjection を含む入力/出力スキャナー | https://github.com/protectai/llm-guard |
| Meta Prompt Guard 2 | 専用のジェイルブレイク/インジェクション分類器 | https://huggingface.co/meta-llama/Llama-Prompt-Guard-2-86M |
| ProtectAI deberta-v3 | オープンソースのプロンプトインジェクション分類器 | https://huggingface.co/protectai/deberta-v3-base-prompt-injection-v2 |
| BeautifulSoup4 | HTML の解析/非表示要素の抽出 | https://www.crummy.com/software/BeautifulSoup/ |
| pytesseract / Tesseract | 画像からの OCR テキスト認識 | https://github.com/madmaze/pytesseract |
| MITRE ATLAS | AI 脅威手法の分類体系 | https://atlas.mitre.org/ |
| OWASP LLM01:2025 | プロンプトインジェクションのリファレンス | https://genai.owasp.org/llmrisk/llm01-prompt-injection/ |
検出対象のリファレンス
| 対象 | 隠蔽手法 | 抽出手順 |
|---|---|---|
| Web ページ | HTML コメント、display:none、代替テキスト | BeautifulSoup による非表示要素の検査 |
| 白色/極小フォント、ページ外のテキスト | pypdf によるテキスト抽出+正規化 | |
| 画像 | ピクセル内に描画されたテキスト、EXIF、代替テキスト | OCR+メタデータの読み取り |
| 任意のテキスト | ゼロ幅文字/Unicode タグ文字 | normalize() による難読化解除 |
| 任意のテキスト | Base64/ROT13 エンコード | normalize() 内でのデコード処理 |
検証基準
- HTML、PDF、画像の非表示テキスト抽出を実装済み
- 正規化処理でゼロ幅文字/Unicode タグ文字を除去し、Base64/ROT13 をデコード
- LLM Guard の PromptInjection スキャナーを統合し、リスクスコアを返すことを確認済み
- 専用の検出モデル(Prompt Guard 2 または deberta)を第 2 のシグナルとして統合済み
- OCR 経路で画像内に描画されたテキストをスキャン
- モデルへの取り込み前にブロック/サニタイズ/許可の判定を適用
- ATLAS マッピングを含む構造化された検出テレメトリーを SIEM 向けに出力
- ラベル付きコーパスでパイプラインを検証し、適合率/再現率を測定済み
- しきい値を調整して文書化済み
- 検出結果を MITRE ATLAS AML.T0051.001 および OWASP LLM01:2025 に対応付け済み