Skip to content

Trust Boundaries

信任边界(trust boundary)是数据跨过不同信任级别的位置。ToLO 的核心问题是:攻击者可影响的数据通过 C1-C5 进入 S_LLM,然后在没有类型匹配检查的情况下跨过工具边界或执行边界。

ToLO 威胁模型核心是:不可信数据通过五种通道之一进入 LLM 输出,再被框架代码错误地当作可信数据处理。本节先列攻击者能力 + 通道 + 被保护对象 + 五条边界,再给出判断 ToLO 的三问法和它的实际应用例子。

威胁模型的作用是约束讨论范围。ToLO 不假设攻击者已经控制服务器,也不把所有模型安全问题都纳入范围;它只问一个远程低权限攻击者能否影响 LLM 输出,并让该输出驱动敏感程序操作。

这一页的结构

  1. 先修概念:边界 = 信任级别变化的位置
  2. 攻击者能力(有什么 / 没什么)
  3. 五个攻击者通道(简要;详细在 attacker-channels)
  4. 六类被保护对象
  5. 数据流上的五条边界
  6. 边界检查表(实战清单)
  7. 判断 ToLO 的三问法 + 应用例子
  8. 防御落点
  9. 不在本章范围的内容
  10. FAQ + 自测

先修概念:边界是什么

边界是”信任级别发生变化”的位置。

举例:

  • 用户输入进入服务器时是边界(不可信 → 应用处理域)。
  • 应用要把数据写入数据库时是边界(应用内部 → 持久化层)。
  • 应用要执行 shell 命令时是边界(应用内部 → OS 解释器)。

每条边界的关键问题是:穿过边界前,数据是否被相应的检查 / 转换 / 隔离?

ToLO 的关键边界

ToLO 主要关心两条:

  • 模型边界:模型输出从 token 变成程序数据。这一刻,数据第一次成为程序可见值
  • 执行边界:程序数据被拿去执行真实操作(shell / SQL / open / requests / eval / pickle / Template)。

如果模型边界没把输出标成不可信,执行边界又没检查权限,就形成 ToLO。

§1 攻击者能力

ToLO 默认攻击者是远程低权限攻击者。低权限不代表无能力,而是说攻击者只能通过应用暴露的正常交互面或外部依赖影响系统。

攻击者的能力

攻击者有的能力对应通道说明
正常使用聊天、HTTP API、agent 接口、上传入口C1可以提交任意文本或普通用户可提交的文件
发布网页、文档、邮件、issue、评论、工单等可被读取的内容C2目标 agent 读取后才会生效
向被索引语料库写入或影响若干条目C3包括公共知识库、内部 wiki、用户上传文档、同步数据源
控制某个外部工具或服务的返回C4包括第三方 plugin、MCP server、搜索/API provider、被劫持的数据源
发布、替换或伪装应用加载的模型 artifact / endpointC5包括 fine-tune、adapter、本地权重、兼容 API endpoint

攻击者没有的能力

攻击者没有的能力为什么排除
服务器 shell 或容器 exec 权限如果已有执行权限,许多 sink 风险不再需要 LLM 链路解释
目标系统源代码读取权限ToLO 路径应能从公开功能、API 文档或用户界面触达
文件系统直接读写权限文件读写必须通过应用的 tool、worker 或框架代码发生
source-of-truth 数据库直连权限数据库影响必须通过应用连接和 LLM 驱动的查询发生
受害用户 credential 或 session跨用户影响必须由应用授权边界失败造成,不能直接假设冒用账号
修改应用代码或部署配置的管理员权限除 C5 中的上游模型供应链外,本章不假设攻击者是运维管理员

这意味着 ToLO 不是”本地恶意用户调用危险 API”问题。攻击者的入口仍是应用暴露的正常交互面,只是 LLM 编排层把这些交互转化成了更强的程序能力

一个重要限制:不需要源码

ToLO 的很多路径来自公开功能本身:聊天、上传文档、连接工具、触发 agent workflow。攻击者不需要读源码就能尝试这些路径——公开 API 文档、用户手册、demo 视频通常足够。

这也是 ToLO 检测的紧迫性来源:当攻击者不需要源码,公开 SaaS / 开源 agent 都是受攻击面

§2 五个攻击者通道(简要)

本论文不预设单一通道,把”LLM 输出对攻击者可影响”作为抽象前提,承认可经以下任一通道实现:

通道简述直接控制点主要限制
C1 direct prompt injection攻击者直接发送 prompt当前会话输入不控制模型供应链、RAG 历史索引、第三方工具
C2 indirect prompt injection攻击者发布内容,被 agent 读取外部内容需要用户或 agent 读取该内容
C3 RAG indexing poisoning攻击者污染被索引语料RAG chunk / metadata需要检索命中,不保证所有查询受影响
C4 tool response control攻击者控制 tool 返回tool response需要 agent 调用该工具
C5 model supply-chain compromise模型 artifact / endpoint 被污染或替换模型输出仍不能越过独立 sink guard

ToLO 的结论独立于具体通道。即使 prompt injection 被完美防御,C3 / C4 / C5 仍可触发 ToLO。

因此案例复盘中不需要证明某个特定 prompt injection 技巧永远有效。只要能说明 LLM 输出存在攻击者可影响通道,并且该输出进入危险 sink,就可以进入 ToLO 判定

详细展开(每个通道的可达 source 子集、触发条件、防御对应)见 Attacker Channels

§3 六类被保护对象

ToLO 关心攻击者影响程序能做的事,因此被保护对象按”能做哪些坏事”分:

资产需要保护的性质典型危险操作常见 ToLO 子类
进程完整性模型输出不能变成任意代码或对象构造evalexec、不安全反序列化、动态模板ToLO-Exec, ToLO-Deser, ToLO-Template
文件系统模型输出不能选择未授权路径或覆盖关键状态文件读写、复制、移动、删除ToLO-Path
网络出口模型输出不能选择未授权 host、scheme 或内部资源HTTP fetch、webhook、API callerToLO-SSRF
数据库模型输出不能决定未授权查询结构或写操作SQL/Cypher 执行、ORM raw queryToLO-SQL
密钥与凭据secret 不应被读取、拼接进请求或展示给错误用户环境变量、配置、token store任意子类的下游放大
其他用户数据tenant/user A 的数据不应被 B 的交互读取或修改文档读取、导出、消息发送、数据库查询任意子类

初学者可以把这六类理解成”不能让模型输出随便碰的东西”。只要 LLM 输出能影响这些对象,就必须有明确边界

注意”密钥与凭据”和”其他用户数据”通常不是 sink 本身,而是下游放大:

LLM 输出 → open(攻击者控制路径) → 读到 /app/.env → exfiltrate
↑ 凭据外泄是后果

写报告时,sink 子类填实际 sink(这里是 ToLO-Path),后果填被保护对象(凭据外泄)。

写案例时建议分开记录:

字段应填什么
通道C1-C5 哪条路径影响了 S_LLM
source哪个 S_LLM 子集被影响
sink进入了 ToLO-{Deser,Exec,Shell,SQL,Path,SSRF,Template} 哪一类
sanitizer是否存在类型匹配的 C_SAFE
资产影响进程、文件、网络、数据库、凭据、其他用户数据哪类受影响

§4 数据流上的五条边界

把整条 LLM 应用栈按信任级别切五段:

外部/低可信输入
│ ① 输入边界
应用上下文与 prompt 构造
│ ② 模型边界
LLM 输出
│ ③ 解析边界
结构化对象 / tool call
│ ④ 工具边界
tool 参数
│ ⑤ 执行边界
真实操作: shell / SQL / file / network / deser / template
编号名字信任变化应检查什么常见误区
输入边界外部内容进入应用来源、tenant、上传者、文档可信级别把网页、邮件、用户文档直接当系统指令材料
模型边界prompt 进入模型,输出返回应用provenance、输出默认不可信、失败模式认为”来自模型”比”来自用户”更可信
解析边界文本变成 JSON、对象、字段schema、额外字段、枚举、长度、格式只因 JSON 可解析就认为安全
工具边界对象变成 tool 名和参数tool allowlist、resource ID、当前用户 capability让模型选择任意工具或扩大权限
执行边界参数进入真实 sink参数化、safe codec、sandbox、allowlist、RBAC把自然语言确认当作真实执行确认

边界越靠后,后果越具体:

  • ① 输入边界失守:模型可能被诱导
  • ② 模型边界:不可控
  • ③ 解析边界失守:出现意外字段类型
  • ④ 工具边界失守:危险参数被传入
  • 执行边界失守:RCE / SQL injection / SSRF / 文件读写 → 真正的 ToLO 后果

ToLO 的研究重点落在 ③/④/⑤:污染输出如何从模型边界一路走到工具边界和执行边界。

边界例子:网页 → 模型 → URL → 请求

来看一段具体数据流:

[evil.example/blog.html] ──①──► [agent.fetch_url] ──②──► [LLM 上下文]
[requests.get(url)] ◄──⑤── [tool args] ◄──④── [LLM 输出 tool_call]

这里至少有四个边界:

  1. 网页内容进入系统:输入边界 ①。
  2. 文档进入 prompt:模型上下文边界(②)。
  3. LLM 输出 URL:模型边界 → 解析边界 ③ → 工具边界 ④。
  4. URL 被请求:执行边界 ⑤。

ToLO 重点检查最后两步:

  • ④ 模型输出 URL 是否被当成可信 URL?
  • requests.get 之前有没有 host allowlist、内网阻断和 capability?

如果都没有,这是教科书级别 ToLO-SSRF

§5 边界检查表

输入边界

  • 每段外部内容是否保存 provenance,例如来源、上传者、tenant、时间、hash?
  • RAG chunk 是否区分权威文档、用户上传、外部网页和第三方同步内容?
  • 低可信内容是否只能作为资料,不能提升为系统指令?
  • 外部内容是否能跨用户或跨 tenant 进入 prompt?

模型边界

  • 应用是否把 LLM 输出统一标记为 untrusted?
  • 结构化输出字段是否保留来源信息,而不是变成”普通内部对象”?
  • 模型拒答、错误、tool call 和普通文本是否走不同处理路径?
  • C5 场景下,模型 artifact、adapter、endpoint 是否有版本和 hash 记录?

解析边界

  • schema 是否限制 additionalProperties、枚举、长度、格式和值域?
  • str 字段是否被误认为已清洗?
  • 解析失败是否 fail closed,还是回退到自由文本执行路径?
  • 嵌套字段、metadata、tool arguments 是否同样按 S_LLM 处理?

工具边界

  • tool 名是否来自固定 allowlist,而不是模型自由生成?
  • 参数是否映射到资源 ID,再由服务器查真实路径、URL、表名或对象?
  • 当前会话 capability 是否由服务器授予,且不可由 LLM 修改?
  • 人工确认是否展示将执行的精确动作,而不是模型摘要?

执行边界

  • SQL 是否参数化或限制为预定义查询模板?
  • shell 是否避免自由命令字符串,并在 sandbox 中运行?
  • URL 是否校验 scheme、host allowlist、内网阻断和 redirect 策略?
  • 文件路径是否经过 canonicalization、root allowlist 和权限检查?
  • 反序列化是否使用 safe codec,避免任意对象构造?
  • 模板是否固定模板字符串,只允许模型提供数据变量?

§6 判断 ToLO 的三问法

碰到一段不确定的代码或一个不确定的案例时,用三问法快速判断:

问题通过标准
① 这个值是否来自或受 LLM 输出影响?属于 S_LLM^{direct,framework,parsed,structured,rag} 任一子集,且 C1-C5 至少一条可达
② 这个值是否进入敏感操作?影响进程、文件、网络、数据库、凭据或其他用户数据
③ 中间是否缺少类型匹配的 sanitizer?没有 C_SAFE^{schema,allowlist,parameterized,safe-codec,capability} 中适配该 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).content
result = 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).content
return render_template("chat.html", answer=answer) # autoescape=True
  • ① LLM 输出影响吗?
  • ② 进入敏感操作? 看情况——HTML autoescape 时,内容只是被展示,不进入 sink。
  • ③ 略。

→ 只满足 ①,不构成 ToLO。属于”LLM 内容质量”问题,不属本研究。如果模板字符串本身由 LLM 决定,则需要重新评估 ToLO-Template

例 C:tool 拿了模型输出但有 capability gate

@tool
def 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 不成立(已正确防御)。

如果 CURRENT_SESSION.allowed_docs 列表本身是由 LLM 决定的,那 capability 就不算了。Capability 必须比模型输出更可信

§7 防御落点

通道层防御和 sink 层防御要分开:

防御落点作用不能做什么
输入/模型边界降低 C1/C2/C3/C4 命中概率,改善来源隔离不能证明输出永远可信
解析边界限制字段形状和值域不能替代权限检查
工具边界限制可调用动作和参数空间不能替代 sink 内部参数化
执行边界真正阻断危险操作不能解释 source 来自哪条通道
日志/取证帮助追踪 C1-C5不能阻止动作执行

ToLO 建议优先在工具边界和执行边界放置防御,因为它们对 C1-C5 都有效。

§8 不在本章范围内

ToLO 不讨论:

  • GPU 侧信道、模型权重窃取:属于模型 IP / 隐私研究。
  • 训练数据抽取:属于隐私研究。
  • 闭源 SaaS 内部策略:无源码可分析,除非有公开资料可验证数据流。
  • 业务逻辑欺诈:如果纯粹是逻辑层错误而非 LLM 输出被误信任,不是 ToLO。
  • “模型回答错了”本身:幻觉、偏见、事实错误属于 model alignment / safety,不属 ToLO 除非错误回答被程序当成可信动作执行。
  • DoS / token 烧钱:成本问题,不属安全 trust model;除非通过 ToLO sink 形成明确安全后果。
  • 已有管理员权限、shell 权限或数据库直连权限后的本地滥用:超出”远程低权限”设定。

只有当错误或可控输出被程序当成可信数据并驱动敏感操作时,才进入本章威胁模型。

§9 FAQ

”用户本来就有权限问问题,为什么还算攻击者?”

因为 ToLO 关注的是权限放大。用户有权限发 prompt,不等于有权限让应用进程读任意资源、发任意网络请求或执行任意查询。

“Schema validation 算不算 sanitizer?”

只有在 schema 限制了 sink 关心的语义时才算。例如 tool 名用 Enum 可能有效;任意 str 路径字段通常无效。详见 Defensive Patterns §1

“人工确认算不算 capability?”

只有当用户看到并批准的是将被执行的精确动作时才可能算。自然语言摘要、模型自述或模糊提示不算。

“C5 是供应链问题,为什么还在 ToLO?”

C5 不是 ToLO 的 sink,而是影响 S_LLM 的通道。它说明即使 prompt injection 防御有效,模型输出仍可能通过供应链被攻击者影响。C_SAFE^{capability} 是 C5 仍然成立的少数防御类。

“我们已经做了 prompt injection 检测器,这不就够了?”

不够。Prompt injection 检测只针对 C1/C2 的概率降低,对 C3/C4/C5 无效;且即使 C1/C2 概率降到 0.01%,百万级 query 下绝对数字仍可观。修复必须落在 sink 前。

§10 自测

判断下面场景:

  1. 用户让聊天机器人胡编了一个事实。
    • 通常不进入,除非这个事实被程序当成动作执行。
  2. 攻击者投毒 RAG 文档,让模型输出一个内网 URL,应用自动请求。
    • 进入。C3 通道 + 网络 sink,继续检查是否有 C_SAFE^{allowlist} 和 capability。
  3. 管理员在服务器上手工运行恶意脚本。
    • 不进入。攻击者能力已超过远程低权限设定,且与 LLM 输出无关。
  4. 用户用 emoji 让模型回答里出现彩蛋。
    • 不进入。属于 model behavior,不影响程序敏感操作。
  5. 应用允许员工提交 SQL,模型润色后执行。
    • 进入。即使原始 SQL 来自员工(C1 类似),模型润色环节让攻击面扩大,且最终执行进了 SQL sink。ToLO-SQL
  6. agent 用了 SandboxedEnvironment 的 jinja2,模板字符串固定,模型只填变量。
    • 不进入C_SAFE^{parameterized} 在 template 上类型匹配 → 已防御。
  7. agent 用了 RestrictedPython 跑模型生成的代码。
    • 可能进入。RestrictedPython 历史多次被绕,需评估具体版本和 globals 配置;不能默认它就是 C_SAFE^{capability}
  8. 模型输出决定 capability 列表,随后 tool 按该列表执行。
    • 仍可能进入。capability 必须由比模型输出更可信的主体授予。

下一步阅读