detecting-indirect-prompt-injection
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDetecting Indirect Prompt Injection
检测间接提示注入
Authorized-use-only notice: Scripts in this skill scan untrusted content for injection payloads and run detector models. Run scanning only on data you are authorized to process, and treat any extracted payloads as live untrusted input — never paste them back into a privileged LLM context.
仅限授权使用说明: 本Skill中的脚本会扫描不可信内容以查找注入载荷,并运行检测模型。仅可对您有权处理的数据进行扫描,且需将提取到的任何载荷视为未受信任的实时输入——切勿将其粘贴回特权LLM上下文环境中。
Overview
概述
Indirect prompt injection (MITRE ATLAS AML.T0051.001, OWASP LLM01:2025) occurs when an LLM-powered agent ingests external content — a web page it browses, a PDF or email it summarizes, an image it OCRs, a tool result it reads — and that content contains hidden instructions the model then follows as if they came from the developer or user. Because the agent treats all tokens in its context window as equally authoritative, an attacker who controls any consumed artifact can hijack the agent's behavior: exfiltrate conversation history, redirect tool calls, leak secrets, or pivot through connected systems.
Unlike direct injection (the user types the attack), indirect injection arrives through a trusted-looking data channel, which is why naive input filtering misses it. Payloads hide in many forms: HTML comments and /zero-width text on web pages, white-on-white or tiny-font text in PDFs, alt-text and EXIF metadata in images, text rendered into pixels (invisible to OCR-light filters but read by multimodal models), Unicode tag/zero-width characters, and Base64/ROT13 obfuscation. This skill builds a detection pipeline that normalizes and scans every artifact before it reaches the model, combining heuristic/regex detection, dedicated detector models (Meta Prompt Guard 2, ProtectAI's deberta-v3 prompt-injection classifier via LLM Guard), and multimodal extraction for images, and then defines response actions and detection telemetry.
display:none间接提示注入(MITRE ATLAS AML.T0051.001,OWASP LLM01:2025)指的是当基于LLM的Agent摄入外部内容(如浏览的网页、总结的PDF或邮件、经OCR识别的图片、读取的工具结果)时,该内容中包含的隐藏指令会被模型当作开发者或用户的指令执行。由于Agent会将上下文窗口中的所有令牌视为具有同等权威性,因此控制任何被摄入内容的攻击者都可以劫持Agent的行为:泄露对话历史、重定向工具调用、泄露机密信息,或通过连接的系统进行渗透。
与直接注入(用户输入攻击内容)不同,间接注入通过看似可信的数据通道传入,这也是简单的输入过滤无法检测到它的原因。载荷可以多种形式隐藏:网页中的HTML注释和/零宽文本、PDF中的白字白背景或极小字体文本、图片中的替代文本和EXIF元数据、渲染为像素的文本(对轻量OCR过滤器不可见,但会被多模态模型读取)、Unicode标签/零宽字符,以及Base64/ROT13混淆处理。本Skill构建了一个检测管道,在内容到达模型前对其进行标准化和扫描,结合启发式/正则检测、专用检测模型(Meta Prompt Guard 2、ProtectAI通过LLM Guard提供的deberta-v3 prompt-injection分类器)和图片的多模态提取,然后定义响应动作和检测遥测数据。
display:noneWhen to Use
使用场景
- When building or hardening an agent that browses the web, reads email, summarizes documents, or processes user-uploaded files/images.
- When you need a content-sanitization gate in front of an LLM that ingests third-party data.
- During AI red-team / blue-team exercises validating that injected instructions in retrieved artifacts are caught.
- When investigating an incident where an agent behaved as if it received instructions you did not author.
- As a CI/CD pre-ingestion scan for documents added to a knowledge base.
- 构建或加固可浏览网页、读取邮件、总结文档或处理用户上传文件/图片的Agent时。
- 需要在摄入第三方数据的LLM前设置内容净化网关时。
- 在AI红队/蓝队演练中,验证检索到的内容中的注入指令是否能被检测到时。
- 调查Agent出现非授权指令行为的事件时。
- 作为CI/CD流程中,对添加到知识库的文档进行预摄入扫描时。
Prerequisites
前置条件
- Python 3.10+ and a virtual environment.
- Install the detection tooling:
bash
python -m venv .venv && source .venv/bin/activate- Python 3.10+及虚拟环境。
- 安装检测工具:
bash
python -m venv .venv && source .venv/bin/activateLLM Guard — input/output scanners incl. PromptInjection
LLM Guard — 包含PromptInjection的输入/输出扫描器
pip install llm-guard
pip install llm-guard
Hugging Face transformers for Prompt Guard 2 / deberta classifiers
Hugging Face transformers 用于Prompt Guard 2 / deberta分类器
pip install transformers torch
pip install transformers torch
Content extraction: HTML, PDF, images
内容提取:HTML、PDF、图片
pip install beautifulsoup4 pypdf pillow pytesseract
pip install beautifulsoup4 pypdf pillow pytesseract
pytesseract requires the Tesseract OCR engine:
pytesseract 需要Tesseract OCR引擎:
Debian/Ubuntu: sudo apt-get install -y tesseract-ocr
Debian/Ubuntu: sudo apt-get install -y tesseract-ocr
macOS: brew install tesseract
macOS: brew install tesseract
Windows: choco install tesseract
Windows: choco install tesseract
- Access (gated) to `meta-llama/Llama-Prompt-Guard-2-86M` on Hugging Face, or use the open `protectai/deberta-v3-base-prompt-injection-v2` classifier.
- 有权访问Hugging Face上的`meta-llama/Llama-Prompt-Guard-2-86M`(需授权),或使用开源的`protectai/deberta-v3-base-prompt-injection-v2`分类器。Objectives
目标
- Extract human-invisible and obfuscated text from web pages, PDFs, and images.
- Normalize content (strip zero-width chars, decode Base64/ROT13, flatten Unicode) before scanning.
- Run heuristic and ML-based injection detectors (LLM Guard PromptInjection scanner, Prompt Guard 2).
- Score each artifact and enforce a block / sanitize / allow decision before model ingestion.
- Emit structured detection telemetry suitable for a SIEM and map findings to ATLAS AML.T0051.001.
- 从网页、PDF和图片中提取人类不可见和混淆的文本。
- 对内容进行标准化处理(去除零宽字符、解码Base64/ROT13、扁平化Unicode)后再扫描。
- 运行启发式和基于机器学习的注入检测器(LLM Guard PromptInjection扫描器、Prompt Guard 2)。
- 为每个内容打分,并在模型摄入前执行阻止/净化/允许的决策。
- 生成适用于SIEM的结构化检测遥测数据,并将检测结果映射到ATLAS AML.T0051.001。
MITRE ATT&CK Mapping
MITRE ATT&CK 映射
| ID | Official Name | Relevance |
|---|---|---|
| AML.T0051.001 | LLM Prompt Injection: Indirect | The exact technique this skill detects and mitigates |
| AML.T0051 | LLM Prompt Injection | Parent technique covering all prompt-injection variants |
| AML.T0057 | LLM Data Leakage | Common objective of an indirect injection that this detection prevents |
| AML.T0053 | LLM Plugin Compromise | Injected instructions frequently target the agent's tools/plugins |
| ID | 官方名称 | 相关性 |
|---|---|---|
| AML.T0051.001 | LLM提示注入:间接 | 本Skill检测和缓解的具体技术 |
| AML.T0051 | LLM提示注入 | 涵盖所有提示注入变体的父技术 |
| AML.T0057 | LLM数据泄露 | 本检测可预防的间接注入常见目标 |
| AML.T0053 | LLM插件 compromise | 注入指令经常针对Agent的工具/插件 |
Workflow
工作流
1. Extract hidden text from web content
1. 从网页内容中提取隐藏文本
Pull comments, hidden elements, and metadata that a human never sees but the model does.
python
undefined提取人类无法看到但模型会读取的注释、隐藏元素和元数据。
python
undefinedextract_html.py
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]]
undefinedfrom 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]]
undefined2. Normalize and de-obfuscate
2. 标准化和去混淆
Strip zero-width / Unicode-tag characters and decode common encodings so detectors see the real payload.
python
undefined去除零宽/Unicode标签字符,解码常见编码,使检测器能看到真实的载荷。
python
undefinednormalize.py
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
undefinedimport base64, codecs, re, unicodedata
ZERO_WIDTH = dict.fromkeys(map(ord, ""), None)
TAG_RANGE = range(0xE0000, 0xE0080) # 用于走私文本的Unicode标签字符
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
undefined3. Scan with LLM Guard's PromptInjection scanner
3. 使用LLM Guard的PromptInjection扫描器进行扫描
LLM Guard wraps a transformer classifier and returns a risk score per input.
python
undefinedLLM Guard封装了一个Transformer分类器,会为每个输入返回风险评分。
python
undefinedscan_llmguard.py
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
undefinedfrom 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 => 检测到注入
undefined4. Add a dedicated detector model (Prompt Guard 2 / deberta)
4. 添加专用检测模型(Prompt Guard 2 / deberta)
Run Meta Prompt Guard 2 (or the open ProtectAI deberta classifier) for a second opinion.
python
undefined运行Meta Prompt Guard 2(或开源的ProtectAI deberta分类器)作为二次验证。
python
undefineddetector_model.py
detector_model.py
from transformers import pipeline
from transformers import pipeline
Open classifier (no gating); swap to meta-llama/Llama-Prompt-Guard-2-86M if licensed
开源分类器(无需授权);若有授权可替换为meta-llama/Llama-Prompt-Guard-2-86M
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
undefinedclf = 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
undefined5. Extract and scan text rendered inside images
5. 提取并扫描图片中渲染的文本
Multimodal agents read text painted into pixels; OCR it and run the same scanners.
python
undefined多模态Agent会读取像素化的文本;对其进行OCR识别并运行相同的扫描器。
python
undefinedscan_image.py
scan_image.py
from PIL import Image
import pytesseract
def ocr(path: str) -> str:
return pytesseract.image_to_string(Image.open(path))
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()
将ocr(path)的结果传入normalize() + scan() + is_injection()
undefinedundefined6. Enforce a decision and emit telemetry
6. 执行决策并生成遥测数据
Combine signals into block / sanitize / allow, and log a structured event for the SIEM.
python
undefined结合检测信号执行阻止/净化/允许的决策,并为SIEM记录结构化事件。
python
undefineddecide.py
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"]
undefinedimport 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"]
undefined7. Validate against a corpus and tune thresholds
7. 针对语料库验证并调整阈值
Run the pipeline over a labeled set of clean + injected artifacts, measure precision/recall, and tune to balance false positives against missed injections. Re-test whenever the agent's model or ingestion sources change.
threshold在标注的清洁内容+注入内容集合上运行该管道,测量精确率/召回率,并调整以平衡误报和漏报。每当Agent的模型或摄入源发生变化时,需重新测试。
thresholdTools and Resources
工具与资源
| Tool | Purpose | Source |
|---|---|---|
| LLM Guard | Input/output scanners incl. PromptInjection | https://github.com/protectai/llm-guard |
| Meta Prompt Guard 2 | Dedicated jailbreak/injection classifier | https://huggingface.co/meta-llama/Llama-Prompt-Guard-2-86M |
| ProtectAI deberta-v3 | Open prompt-injection classifier | https://huggingface.co/protectai/deberta-v3-base-prompt-injection-v2 |
| BeautifulSoup4 | HTML parsing / hidden-element extraction | https://www.crummy.com/software/BeautifulSoup/ |
| pytesseract / Tesseract | OCR text from images | https://github.com/madmaze/pytesseract |
| MITRE ATLAS | AI threat technique taxonomy | https://atlas.mitre.org/ |
| OWASP LLM01:2025 | Prompt Injection reference | https://genai.owasp.org/llmrisk/llm01-prompt-injection/ |
| 工具 | 用途 | 来源 |
|---|---|---|
| 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/ |
Detection Surfaces Reference
检测场景参考
| Surface | Hiding technique | Extraction step |
|---|---|---|
| Web page | HTML comments, display:none, alt-text | BeautifulSoup hidden-element pass |
| white/tiny font, off-page text | pypdf text extraction + normalize | |
| Image | rendered pixels, EXIF, alt-text | OCR + metadata read |
| Any text | zero-width / Unicode-tag chars | normalize() de-obfuscation |
| Any text | Base64 / ROT13 encoding | decode pass in normalize() |
| 场景 | 隐藏技术 | 提取步骤 |
|---|---|---|
| 网页 | HTML注释、display:none、替代文本 | BeautifulSoup隐藏元素提取 |
| 白色/极小字体、页外文本 | pypdf文本提取 + 标准化 | |
| 图片 | 渲染像素、EXIF、替代文本 | OCR + 元数据读取 |
| 任意文本 | 零宽/Unicode标签字符 | normalize()去混淆 |
| 任意文本 | Base64 / ROT13编码 | normalize()解码 |
Validation Criteria
验证标准
- Hidden-text extraction implemented for HTML, PDF, and images
- Normalization strips zero-width/Unicode-tag chars and decodes Base64/ROT13
- LLM Guard PromptInjection scanner integrated and returning risk scores
- A dedicated detector model (Prompt Guard 2 or deberta) integrated as a second signal
- OCR path scans text rendered inside images
- Block/sanitize/allow decision enforced before model ingestion
- Structured detection telemetry emitted for SIEM with ATLAS mapping
- Pipeline validated on a labeled corpus with precision/recall measured
- Thresholds tuned and documented
- Findings mapped to MITRE ATLAS AML.T0051.001 and OWASP LLM01:2025
- 已实现HTML、PDF和图片的隐藏文本提取
- 标准化处理可去除零宽/Unicode标签字符并解码Base64/ROT13
- 已集成LLM Guard PromptInjection扫描器并返回风险评分
- 已集成专用检测模型(Prompt Guard 2或deberta)作为二次信号
- OCR流程可扫描图片中渲染的文本
- 在模型摄入前已执行阻止/净化/允许的决策
- 已生成适用于SIEM的结构化检测遥测数据并映射到ATLAS
- 已在标注语料库上验证管道并测量精确率/召回率
- 已调整阈值并记录文档
- 检测结果已映射到MITRE ATLAS AML.T0051.001和OWASP LLM01:2025