Trust Boundaries
ToLO 威胁模型核心是:不可信数据通过五种通道之一进入 LLM 输出,再被框架代码错误地当作可信数据处理。本节先列攻击者能力 + 通道 + 被保护对象 + 五条边界,再给出判断 ToLO 的三问法和它的实际应用例子。
威胁模型的作用是约束讨论范围。ToLO 不假设攻击者已经拿到服务器 shell,也不研究模型训练阶段的全部攻击;它只关心一个远程低权限攻击者能否影响 LLM 输出,并让该输出触达敏感程序操作。
这一页的结构
- 先修概念:边界 = 信任级别变化的位置
- 攻击者能力(有什么 / 没什么)
- 五个攻击者通道(简要;详细在 attacker-channels)
- 六类被保护对象
- 数据流上的五条边界
- 判断 ToLO 的三问法
- 不在本章范围的内容
- 自测
先修概念:边界是什么
边界是”信任级别发生变化”的位置。
举例:
- 用户输入进入服务器时是边界(不可信 → 应用处理域)。
- 应用要把数据写入数据库时是边界(应用内部 → 持久化层)。
- 应用要执行 shell 命令时是边界(应用内部 → OS 解释器)。
每条边界的关键问题是:穿过边界前,数据是否被相应的检查 / 转换 / 隔离?
ToLO 的关键边界
ToLO 主要关心两条:
- 模型边界:模型输出从 token 变成程序数据。这一刻,数据第一次成为程序可见值。
- 执行边界:程序数据被拿去执行真实操作(shell / SQL / open / requests / eval / pickle / Template)。
如果模型边界没把输出标成不可信,执行边界又没检查权限,就形成 ToLO。
§1 攻击者能力
攻击者有的能力
ToLO 假设攻击者是远程低权限用户:
- ✅ 可以与目标 LLM 应用正常交互(发送 prompt、提交表单、上传文件 等)。
- ✅ 可以提供任意文本输入(包括其他用户能看到的评论、issue、commit 描述等)。
- ✅ 可以发布公开内容(网页、博客、issue、PR、文档),让被 agent 抓取或被 RAG 索引。
- ✅ 可以控制某个第三方工具的响应(自己运营的 MCP server、被劫持的 API、伪造的搜索结果)。
- ✅ 可以发布或替换被应用加载的模型权重(恶意 HuggingFace 上传、劫持反向代理 endpoint)。
攻击者没有的能力
- ❌ 目标系统的代码读取(不能
cat src/)。 - ❌ 目标系统的 shell access(不能 SSH 进去)。
- ❌ 文件系统直接访问(不能
ls /etc/)。 - ❌ 数据库直连(不能
psql -h db)。 - ❌ 受害用户的 credential(不能用 X 用户的 cookie / session)。
这意味着 ToLO 不是”本地恶意用户调用危险 API”问题。攻击者的入口仍是应用暴露的正常交互面,只是 LLM 编排层把这些交互转化成了更强的程序能力。
一个重要限制:不需要源码
ToLO 的很多路径来自公开功能本身:聊天、上传文档、连接工具、触发 agent workflow。攻击者不需要读源码就能尝试这些路径 —— 公开 API 文档、用户手册、demo 视频通常足够。
这也是 ToLO 检测的紧迫性来源:当攻击者不需要源码,公开 SaaS / 开源 agent 都是受攻击面。
§2 五个攻击者通道(简要)
本论文不预设单一通道,把”LLM 输出对攻击者可影响”作为抽象前提,承认可经以下任一通道实现:
| 通道 | 简述 | 能力前提 |
|---|---|---|
| C1 直接 prompt injection | 攻击者直接发送 prompt | 用户即攻击者(零前置) |
| C2 间接 prompt injection | 攻击者发布网页/文档,被 agent 抓取或 RAG 检索进 prompt | 能发布公开内容 |
| C3 RAG 索引投毒 | 攻击者控制被索引语料库中的若干条目 | 能写向量库 / wiki / 知识库 |
| C4 工具响应控制 | 攻击者控制 LLM 调用的工具(搜索 API、MCP server、第三方 plugin)返回内容 | 能运营或劫持第三方服务 |
| C5 模型供应链污染 | 攻击者发布或替换被应用加载的模型权重 / endpoint | 能在模型仓库上传或控制反代 |
ToLO 的结论独立于具体通道。即使 prompt injection 被完美防御,C3 / C4 / C5 仍可触发 ToLO。
因此案例复盘中不需要证明某个特定 prompt injection 技巧永远有效。只要能说明 LLM 输出存在攻击者可影响通道,并且该输出进入危险 sink,就可以进入 ToLO 判定。
详细展开(每个通道的可达 source 子集、触发条件、防御对应)见 Attacker Channels。
§3 六类被保护对象
ToLO 关心攻击者影响程序能做的事,因此被保护对象按”能做哪些坏事”分:
| 被保护对象 | 不应被攻击者影响的事 | 典型 ToLO 子类 |
|---|---|---|
| 进程完整性 | 执行攻击者指定代码 | ToLO-Exec, ToLO-Deser |
| 文件系统 | 读写攻击者指定路径,特别是 /etc/、~/.ssh/、应用密钥目录 | ToLO-Path |
| 网络出口 | 请求攻击者指定 URL,特别是内网与 cloud metadata endpoint | ToLO-SSRF |
| 数据库 | 执行攻击者指定 SQL,特别是 DROP / UPDATE / 条件操纵 | ToLO-SQL |
| 密钥与凭据 | 环境变量、配置、API key、token 外泄 | 任意子类的下游放大 |
| 其他用户的数据 | 多用户应用中 A 的数据被 B 的 LLM 交互泄露或修改 | 任意子类 |
初学者可以把这六类理解成”不能让模型输出随便碰的东西”。只要 LLM 输出能影响这些对象,就必须有明确边界。
注意”密钥与凭据”和”其他用户数据”通常不是 sink 本身,而是下游放大:
LLM 输出 → open(攻击者控制路径) → 读到 /app/.env → exfiltrate ↑ 凭据外泄是后果写报告时,sink 子类填实际 sink(这里是 ToLO-Path),后果填被保护对象(凭据外泄)。
§4 数据流上的五条边界
把整条 LLM 应用栈按信任级别切五段:
[攻击者控制] ──①──► [应用内可见] ──②──► [模型黑盒] │ ③ ▼[结构化对象] ◄──④── [tool 参数] ◄──⑤── [真实执行环境]五条边界:
| 编号 | 名字 | 信任变化 | 检查内容 |
|---|---|---|---|
| ① | 输入边界 | 外部 → 应用内 | 用户输入 / 网页 / 上传 / RAG 进入 prompt 时的验证 / 内容来源标记 |
| ② | 模型边界 | 应用 → 模型 | 没什么应用层能检查(模型内部),只能在 prompt 设计上做隔离 |
| ③ | 解析边界 | 模型 → 应用可读对象 | OutputParser / function calling / JSON parser 转结构化 |
| ④ | 工具边界 | 应用对象 → 工具参数 | agent / workflow 把字段传给 tool 前的检查 |
| ⑤ | 执行边界 | 工具参数 → 真实操作 | tool 内部进入 sink 前的最后检查(sanitizer 应当在这里) |
边界越靠后,后果越具体:
- ① 输入边界失守:模型可能被诱导
- ② 模型边界:不可控
- ③ 解析边界失守:出现意外字段类型
- ④ 工具边界失守:危险参数被传入
- ⑤ 执行边界失守:RCE / SQL injection / SSRF / 文件读写 → 真正的 ToLO 后果
ToLO 的研究重点落在 ③/④/⑤:污染输出如何从模型边界一路走到工具边界和执行边界。
§5 边界例子:网页 → 模型 → URL → 请求
来看一段具体数据流:
[evil.example/blog.html] ──①──► [agent.fetch_url] ──②──► [LLM 上下文] │ ③ ▼[requests.get(url)] ◄──⑤── [tool args] ◄──④── [LLM 输出 tool_call]这里至少有四个边界:
- 网页内容进入系统:输入边界 ①。
- 文档进入 prompt:模型上下文边界(②)。
- LLM 输出 URL:模型边界 → 解析边界 ③ → 工具边界 ④。
- URL 被请求:执行边界 ⑤。
ToLO 重点检查最后两步:
- ④ 模型输出 URL 是否被当成可信 URL?
- ⑤
requests.get之前有没有 host allowlist、内网阻断和 capability?
如果都没有,这是教科书级别 ToLO-SSRF。
§6 判断 ToLO 的三问法
碰到一段不确定的代码或一个不确定的案例时,用三问法快速判断:
① 这个值是否来自或受 LLM 输出影响?(含 C1-C5 任一通道)
② 这个值是否进入了会改变程序行为的敏感操作?(六类被保护对象之一)
③ 中间是否缺少与 sink 类型匹配的验证、约束、隔离或人工确认?
三问都成立 → 进入 ToLO 分析。
边界情况
- 只有①成立(LLM 输出存在,但没进敏感操作) → 通常只是 LLM 内容安全或 prompt injection 问题,不是 ToLO。
- 只有①②成立(进了敏感操作,但有看似的 guard) → 看 guard 是否真的类型匹配。错配的 guard 不算 sanitizer。
- 三问都成立但 guard 是”人工确认” → 还要确认人看到的是将被执行的真实动作(精确路径、精确 SQL、精确 URL),而不是模型给出的自然语言摘要(“我准备读一个 config 文件” — 含糊,不算 guard)。
三问法应用例子
例 A:LangChain LLMMathChain(CVE-2023-29374)
# 简化伪代码expr = llm.invoke(prompt).contentresult = PythonREPL().run(expr)- ① LLM 输出影响吗? 是(C1: 用户问”算 2024 的平方” 可能被改成”算
__import__('os').system(...)”) - ② 进入敏感操作? 是(
PythonREPL.run=exec) - ③ 缺类型匹配 guard? 是(无 sandbox、无 capability、无
numexpr等收窄)
→ ToLO 三问全成立 → ToLO-Exec 案例。
例 B:LLM 输出文本仅展示到聊天框
answer = llm.invoke(question).contentreturn render_template("chat.html", answer=answer) # autoescape=True- ① LLM 输出影响吗? 是
- ② 进入敏感操作? 看情况 — HTML autoescape 时,内容只是被展示,不进入 sink。
- ③ 略。
→ 只满足 ①,不构成 ToLO。属于”LLM 内容质量”问题,不属本研究。
例 C:tool 拿了模型输出但有 capability gate
@tooldef read_doc(doc_id: str) -> str: """读取指定文档""" if doc_id not in CURRENT_SESSION.allowed_docs: # ← capability raise PermissionError() real_path = DOC_REGISTRY[doc_id] # ← allowlist 映射 return Path(real_path).read_text()- ① LLM 输出影响吗? 是
- ② 进入敏感操作? 是(
open) - ③ 缺类型匹配 guard? 否 —
capability+allowlist双重 sanitizer,且都类型匹配。
→ ToLO 不成立(已正确防御)。
如果 capability 列表本身是 LLM 决定的,那 capability 就不算了。Capability 必须比模型输出更可信。
§7 不在本章范围内
ToLO 不讨论:
- GPU 侧信道、模型权重窃取:属于模型 IP / 隐私研究。
- 训练数据抽取:属于隐私研究。
- 闭源 SaaS 内部策略:无源码可分析。
- 业务逻辑欺诈:如果纯粹是逻辑层错误而非 LLM 输出被误信任,不是 ToLO。
- “模型回答错了”本身:幻觉、偏见、事实错误属于 model alignment / safety,不属 ToLO 除非错误回答被程序当成可信动作执行。
- DoS / token 烧钱:成本问题,不属安全 trust model。
只有当错误或可控输出被程序当成可信数据并驱动敏感操作时,才进入本章威胁模型。
§8 自测
判断下面场景是否进入 ToLO 威胁模型:
- 用户让聊天机器人胡编了一个事实。
- 通常不进入,除非这个事实被程序当成动作执行。
- 攻击者投毒 RAG 文档,让模型输出一个内网 URL,应用自动请求。
- 进入。C3 通道 +
ToLO-SSRF。
- 进入。C3 通道 +
- 管理员在服务器上手工运行恶意脚本。
- 不进入。攻击者能力已超过远程低权限设定,且与 LLM 输出无关。
- 用户用 emoji 让模型回答里出现彩蛋。
- 不进入。属于 model behavior,不影响程序敏感操作。
- 应用允许员工提交 SQL,模型润色后执行。
- 进入。即使原始 SQL 来自员工(C1 类似),模型润色环节让攻击面扩大,且最终执行进了 SQL sink。
ToLO-SQL。
- 进入。即使原始 SQL 来自员工(C1 类似),模型润色环节让攻击面扩大,且最终执行进了 SQL sink。
- agent 用了
SandboxedEnvironment的 jinja2,模板字符串固定,模型只填变量。- 不进入。
C_SAFE^parameterized在 template 上类型匹配 → 已防御。
- 不进入。
- agent 用了 RestrictedPython 跑模型生成的代码。
- 可能进入。RestrictedPython 历史多次被绕,需评估具体版本和 globals 配置;不能默认它就是
C_SAFE^capability。
- 可能进入。RestrictedPython 历史多次被绕,需评估具体版本和 globals 配置;不能默认它就是
下一步阅读
- 五类攻击者通道详解:C1-C5 各自的能力前提、触发条件与可达 source 子集。
- Sources and Sinks:把这些边界转换成静态分析能识别的 source / sink / sanitizer 集合。
- Core ToLO Patterns:七子类回顾 + sink 端识别。