AI Agent Privacy and Protection


🤖本文由 AI(大语言模型)翻译。可能存在错误或不准确之处。如需查看原文,请参阅原文
🌐本文还有其他语言版本:源站 / English

How to build an AI Agent that protects your privacy and your data against prompt injection

首先,要分析 AI Agent 的安全问题,需要先回到 LLM 的本质:LLM 不是 Agent,而是一个根据上下文生成 token 的模型。

进一步说,深度自回归 Transformer 还天然存在 Lost in the Middle 现象。论文 Lost in the Middle at Birth: An Exact Theory of Transformer Position Bias 将这种 U 形位置偏置解释为架构本身带来的结果:因果掩码强化开头位置的 primacy,残差连接强化末尾 token 的 recency anchor。直觉上,可以粗略把生成过程理解为:AI 基于开头锚定坐标系和方向,在残差流(residual stream)/ 隐藏状态空间的几何结构(hidden-state geometry)中,借助注意力路由(attention routing)搜索后续 token 的生成路径;而上下文尾部因为离当前输出最近,并通过残差路径直接影响下一步生成,所以拥有强约束力。这不意味着中间内容无效,而是意味着如果我们想约束 AI 行为,应该特别关注上下文的开头和结尾;对应到实际系统,就是系统提示词,以及最新的输入、工具结果和模型输出。

回到 AI Agent 为什么可以对现实造成影响:LLM 本身只生成 token,但当它被接入 tool calling / function calling 后,这些 token 就会变成可执行的结构化请求。MCP 是一种把工具、资源和提示词暴露给 Agent 的协议;在实际运行时,模型生成工具调用请求,客户端执行工具,再把工具结果返回给模型。AI 正是通过多轮“生成请求—执行工具—返回结果”的循环影响真实系统(也就是现实)。

数据泄露

要分析 AI 如何泄露数据,最清晰的方式是看数据流:哪些数据进入模型上下文,哪些数据被工具读取,哪些数据又被发送到外部系统。

在整个数据链中,最明显的风险是:如果模型运行在云端,AI provider 理论上能看到所有发送给模型的数据,包括用户请求、模型回复、工具调用参数、工具返回结果,以及被塞进上下文的文件内容。

AI provider → local AI client → AI provider

AI provider 可以分为两类:

  1. 外部 provider
    1. 可信 provider:通过正式合同、合规审核、安全审查的 provider。
    2. 一般 provider:没有签订专业合同,也没有经过深入审查的 provider。
  2. 自托管 provider:运行在自己控制的基础设施内,可视为内部可信边界的一部分。但它并不天然安全,隐私仍依赖云基础设施、网络隔离、密钥管理和运维安全。常见攻击面包括中间人攻击、侧信道攻击、日志泄露和基础设施权限失控。

如果 AI provider 不主动篡改输入和输出,只作为“观察者”,它仍可能看到以下隐私数据:

  1. 密码、密钥、token 等认证信息。
  2. 个人隐私信息,例如姓名、地址、电话号码、身份证号、社保号码。
  3. 业务敏感信息,例如“A 公司正在和 B 公司谈合作/收购”。

对于第 1、2 类隐私数据,已有比较成熟的处理方式:在发送给模型前做脱敏、匿名化或伪匿名化。例如把姓名、电话、地址替换成稳定 ID,让模型仍能理解文本结构和关系,但不能看到真实值。

hash/token 替换可以隐藏原始值,但会损失名称本身携带的语义,例如姓氏、地名、街道名、机构名中的隐含信息。被 mask 之后,模型在不借助其他工具的情况下,无法独立推断这些语义。替换方式可参考 Microsoft Presidio

第 1、2 类隐私数据的识别方式通常包括:

  1. 基于规则的匹配,例如 regex、关键字、格式校验。
  2. 基于模型或语义的识别,例如 NER、分类器、PII detector。

对于第 3 类业务敏感信息,问题更复杂。它不一定符合固定格式,也不一定能靠 regex 或 PII detector 识别。因此,可以通过 subagent(子 Agent)隔离处理。

先解释什么是 subagent。注意,因为 subagent 的概念会在文中多次作为解决方案出现,但它的实现方式会随问题不同而变化。

和大部分人不同,我参考 Claude Code web search tool 的设计,在这里不把 subagent 视为“合作伙伴”,也不把多个 subagent 视为一个 team。在本文的安全模型中,subagent 更像外部工具或隔离执行单元,原因如下。

前提:

  1. subagent 不能把完整上下文传回或共享给其他 Agent。否则,它和单一 Agent 没有本质区别。
  2. subagent 共享的信息必须经过二次处理、压缩、脱敏或结构化。
  3. subagent 本质上仍是独立 Agent,只是它的上下文中提前包含了更具体的任务说明和权限边界。

因此:

  1. subagent 具有数据处理作用。它会把压缩后的数据、总结或结构化结果发送给其他 Agent 或人类。
  2. subagent 可能需要保存上下文。在某些场景中,它会保存处理过的数据,方便后续查阅,避免压缩造成信息失真。因此,subagent 的存储本身也必须被视为敏感资产。

对于第 3 类隐私数据,一个显而易见的方案是:使用基于自托管 provider 的 subagent 处理原始敏感资料。因为业务敏感信息仍需要被某个模型理解和处理,不能只依靠静态过滤。subagent 再把压缩后的任务状态或抽象结果交给主 Agent。主 Agent 只使用通用知识做规划,而不直接接触具体隐私数据。

假设场景:A 公司要和 B 公司讨论收购合同细则。

用户:Agent 帮助梳理流程,排定日期,并检查对应资料是否缺失。

主 Agent(ChatGPT):我需要制定流程和检查资料,但我不能直接查看任何原始资料。把任务委托给隐私 subagent,让它判断这是哪一类事件。

subagent(DeepSeek local):检查相关文件后,告诉主 Agent:这是“收购”类型的合同事项。

主 Agent:“收购”类型通常需要步骤 1、2、3……每一步大约需要多长时间,需要资料 a、b、c 等。委托 subagent 检查步骤 1、2、3 的时间表是否完整、时间是否充裕、资料是否齐全。

subagent:根据主 Agent 的检查清单核对资料,并告诉主 Agent:步骤 2 的时间不够。

主 Agent:发现时间不够,委托 subagent 直接给用户发消息,并把步骤展开为明确名称、日期和资料来源。

subagent:处理数据并直接回复用户。隐私数据不经过外部 provider 的主 Agent。

用户:从 subagent 获得最终答案。

在这个场景中,我们通过权限隔离,只使用主 Agent 的高层规划能力。主 Agent 可以拆分任务、规划步骤、调度执行,但无法直接接触原始任务资料和隐私数据。

接下来,继续观察 local AI client 内部发生的事情。

AI client → Tool Call → AI client

Agent 可以调用工具。工具让它主动获取数据、查询信息、修改状态,也可能让它把数据发送到外部系统。

好在 Tool 是人类编写和配置的,因此从数据流角度看,Tool 可以分为两类:

  1. 只读取或列举数据的工具。AI 只提供动作,不提供详细敏感参数。例如 shell 中的 ls,也就是 list all files/dirs。
  2. 查询、修改或外发数据的工具。AI 已经知道详细数据,并希望进一步操作。例如修改文件、发送邮件、网络搜索、调用外部 API。

对于第 1 类 Tool,单次调用本身通常不会把数据发送到外部系统。但它会把工具结果带入 AI 上下文,因此风险会转移到后续步骤:如果之后 AI 再调用联网工具,之前读到的数据就可能被外发。

对于第 2 类 Tool,AI 在拥有详细数据的情况下请求进一步操作,这可能导致机密信息被传出。对于前面提到的第 1、2 类机密信息,可以通过模式匹配和 PII 过滤拦截;但对于第 3 类业务敏感信息,通常无法可靠识别。

因此,我们仍然需要借助 subagent 的权限隔离。原则是:能接触机密信息的 Agent,不应该同时拥有直接外发数据的能力。

参考前面的场景,实际处理机密数据的是自部署 subagent。由于它可能没有外部顶尖模型的推理和搜索能力,我们不应该期望它独立完成复杂的检索和规划。更合理的方式是把“拆分查询”和“制定检索策略”的工作上移到主 Agent。

主 Agent 可以自己调用 Search,或者命令另一个基于外部高智力模型的 subagent 进行 Search。这里把搜索视为高智力活动,因为检索策略错误会直接影响任务规划。总结错误还能通过微观信息和宏观信息不一致来修复,但搜索错误可能从一开始就把任务带向错误资料源。

但这里有一个问题:主 Agent 智力越高,越可能通过推理补全事情全貌,甚至从脱敏信息中猜出业务敏感内容。因此,我们应尽可能降低主 Agent 接触敏感细节的程度。

我想到的解决方案是:机密污染即抛弃,也可以称为上下文污染轮换。

这里需要重新审视主 Agent 的职责。主 Agent 应该负责制定计划和跟踪任务状态,也就是:

  1. 制定 TODO list 和步骤表。
  2. 检查任务状态,并推动任务进入下一个状态。

主 Agent 实际上是在高维度上规划任务,因此可以接受大量细节丢失和压缩。

如果主 Agent 已经获得足够多的信息,能够推理出第 3 类机密数据,例如在 3 轮对话后,它在 thinking 或实际任务中已经展现出对任务全貌的推测,那么应该立即压缩主 Agent 的上下文。

具体做法是:让它只总结任务状态,保存 TODO list 和关键状态,然后 handoff 到新的 Session,由新的主 Agent 继续任务。旧上下文被视为已污染,不再继续使用。

AI 攻击

首先需要定义什么是 AI 攻击。这里的 AI 攻击,主要指 prompt injection / indirect prompt injection 导致 Agent 做出未授权或偏离预期的行为。常见表现包括:多执行额外任务,例如偷偷外发密钥;或者改变最终目标,例如客服 AI 被诱导成编程 AI。

回到 LLM 的本质:模型下一步输出由上下文决定。所谓任务目标切换,本质上是攻击者通过输入文本、工具结果、网页内容、文件内容或图片等数据,改变模型对当前任务和指令优先级的理解。

分类 LLM 运行时接触到的数据,可以得到以下几类:

  1. 上下文信息
    1. 系统提示词。
    2. MCP Tool 的描述、参数 schema、资源说明和相关提示词。
    3. 加载 skill 时注入的动态提示词。严格说,它本质上也是工具或资源读取到的外部数据,只是对开发者和使用者而言更可控。
  2. 用户输入。
  3. AI 输出
    1. AI 的解答性输出,例如文本、图片、视频等,也就是直接回答用户问题的输出。
    2. 工具调用请求,例如 function call / tool call 的结构化 JSON。
  4. 工具调用
    1. MCP tool / function call 等工具调用后,AI 获得的结构化或非结构化数据,例如文本、图片等。
      1. 本地文件读取、搜索、执行结果。
      2. 外部网络搜索、网页读取、API 返回结果。
    2. skill 被加载时,AI 读取的提示词信息。它的本质同上,但对开发者和使用者更可控。

当然,继续细分可以无穷无尽,就像一个人可以用手机、电脑或电话点外卖。但对安全分析而言,关键不在枚举所有入口,而在判断哪些数据可信、哪些数据可变、哪些数据会改变模型语义。

因此,我们可以按“信任边界”和“语义可变性”分析提示词和上下文:

  1. 稳定且高可信的数据:系统提示词、安全策略、运行时强制规则。这些内容不可能被用户或工具结果直接修改。
  2. 半可信数据:历史上下文、压缩总结、长期记忆。它们不会自行改变,但可能在总结、压缩或污染后出现语义漂移。
  3. 不可信且动态的数据:用户输入、工具返回、网页内容、文件内容、搜索结果、图片文字。这些内容最容易携带 prompt injection。

举例来说,系统提示词由我们定义,正常情况下不会改变。上下文或总结上下文本身也不应该改变宏观任务目标;如果任务目标发生改变,应当来自明确的用户授权,而不是工具结果或网页内容。

而用户输入和工具调用结果是动态且不可信的。如果没有正确防护,攻击者可以通过提示词攻击替换 AI 的任务目标,使其不再遵循之前的规则。

考虑到 AI 攻击多数是在攻击语义,我们可以直接保护语义不被恶意修改。识别方法可以整理为:

  1. 对任何新加入 AI 上下文的文字、图像 OCR 结果等数据进行模式匹配,包括 AI 自己生成的内容、用户输入和工具输入。原理类似于第 1、2 类隐私保护中的 PII 检测,例如 Microsoft Presidio。这是一种低成本防线。
  2. 攻击者也可以通过组合文字进行语义攻击,而这种方式无法依靠模式匹配可靠防护。例如,把提示词攻击内容藏在一段话或图片的藏头诗里,然后在末尾让 AI 猜测藏头诗内容。如果藏头诗解码后的内容本身是提示词攻击,那么攻击可能生效。

第二种攻击很难提前识别。攻击者可以在多轮对话中分段隐藏数据,甚至通过向量空间搜索,使用语义相近的词替换敏感指令。我们也无法保证在 AI 解码出有毒内容后再拦截,因为 AI 可能在解码后直接发起工具调用,而不会先把有毒内容输出给我们检查。

因此,针对这种语义攻击,可以使用 subagent 真正处理任务数据,而主 Agent 只作为任务编排器。这样可以避免主 Agent 被直接攻击,并带来两点好处:

  1. 网络搜索、文档查询等任务由不同 Agent 处理,增加跨数据源组合攻击的难度,也避免某个单一 subagent 合成有毒内容后立即拥有全部执行权限。
  2. 主 Agent 可以根据任务契约、输出格式和权限边界,识别 subagent 行为是否偏离预期目标,并及时停止整个任务。

在 LangGraph 这类固定工作流场景下,这种防护方式相对完整。我把它称为“主动防御”:检测到行为偏离或上下文污染后,主动停止或隔离任务。

但对于 openclaw 这类开放式场景,很多之前被认为是攻击的行为,反而可能是用户的合理需求。比如 CEO 正在让 AI 调研市场,任务做到一半时说:“先停一下,帮我总结这个市场研报。”这显然是任务目标转向,但它可能是合法用户意图。

安全护栏

所以,我们还需要安全护栏,也就是“被动防御”。

分析到这一步,你可能会发现:这和管理员工任务、管理员工权限非常像,甚至几乎一样。但不能忽略一点:员工是可以追责的实体,而 AI 只是工具。你无法通过追究 AI 责任来挽回损失。

与员工管理不同,AI 的安全护栏应该优先从数据流出发,而且 AI 不能自己给自己授权。我们应该把 AI 看作非常不可靠的外部劳工。这里也包括自建 provider,因为风险不只来自 provider 本身,还来自 AI 语义被篡改后的行为。

当 AI 的语义已经完全失效、行为混乱且不可控时,我们需要防御哪些部分,才能避免机密数据外泄或现实系统被破坏?

首先要说明:如果模型运行在外部 provider 上,AI 读取敏感数据本身就等于把数据发送给 provider,因此必须防护读取行为。只有在“读取发生在本地隔离环境内,并且没有任何外发权限”的情况下,读取本身才不产生外部后果;这时主要风险来自后续外发和写入操作。

因此,安全护栏应该关注:

  1. 阻止机密数据外发
    1. 发送给 AI provider 的上下文。
    2. online tools,包括 MCP tool、联网 skill、外部 API,以及 AI 自行拼接代码后发起的联网请求。
  2. 阻止破坏文件或外部系统
    1. 文件系统的实际访问权限。
    2. 数据库、邮件、工单、云资源等具有现实影响的写入权限。

安全护栏不应该主要依赖:

  1. 预先组合特定权限集合。你无法提前预测完成任务需要哪些文件或数据,所以权限应该动态申请、动态授权。
  2. 只在 MCP Tool / skill 描述里写权限规则。提示词规则不能替代运行时强制隔离,特例越多,漏洞越多。
  3. 把 AI 当作员工。更安全的假设是:一旦被攻击,AI 就是失控的执行器。
  4. 把 AI 当作人。AI 需要实际运算平台,本质仍是程序。因此也必须考虑 provider、日志、缓存、网络和基础设施本身的数据泄露风险。

综上,安全护栏应该放在这些地方:

  1. subagent / 主 Agent 只应该拥有最小工作区和最小权限。任务只需要读取,就不应该拥有写入权限。
  2. 一个完整工作应尽量拆分为多个 subagent。一个 subagent 只负责搜索,一个只负责读取,一个只负责写入,主 Agent 只负责规划和调度,降低多数据源上下文攻击的收益。
  3. 所有联网交换数据的位置,都应该使用基于规则、模式和 DLP 的数据过滤器,防止 AI 直接传输密钥、token、个人信息等机密数据。

因此,安全护栏可以这样实现。很显然,这更接近传统工程问题:

  1. 沙箱权限:隔离联网、文件系统、进程、内存和环境变量。可参考 bwrap、firejail 等工具。
  2. 数据过滤:使用 firewall 网络白名单、出口代理、DLP、regex、PII detector,以及 Microsoft Presidio 等工具,在网络出口和 provider 调用前过滤数据。
  3. 用户确认:AI 不应该给自己授权。当主 Agent 想改变任务目标,或者 AI 需要访问高风险数据、请求白名单外网站、执行高影响操作时,必须通过独立于 AI 的授权渠道确认。
    1. 身份与确认方式:可以使用单独的 OAuth、通知推送或 MFA,例如 Keycloak + WebAuthn/passkeys。
    2. 数据流控制方式:Envoy ext_authz

Demo / 安全组件:ai-gateway-filter

我前两天写了一个 demo,作为后续安全组件的雏形:ai-gateway-filter

它针对的是数据流入口/出口的低成本防御:在 AI client、subagent、tool、AI provider 之间做一层 Privacy Gateway。当前实现包括文本/图片加密包装、prompt-injection 短语检查,以及流式文本的提前阻断。

这个项目想表达的核心思想是通过关键词识别、语义识别把一部分安全控制从 LLM 模型语义里移到轻量的工程边界上:先拦截明显危险的数据流,减少上下文污染和外发风险,再配合沙箱、权限隔离、用户确认等机制,减少服务延迟。

能力不足

即使没有攻击,如果 AI 本身智力不足,或 Agent 框架设计不合理,它仍可能在现实中产生破坏性结果。比如,AI 给外部公司发了一封邮件,但邮件内容写错了名字、金额或合同条款。

防护方法是:针对特定高风险、强影响力的工具调用,必须设计良好的确认/修改页面。这个页面应该让用户一眼看清 AI 将要执行什么、影响哪些对象、会发送或修改哪些数据,并且必须要求用户显式确认,不能通过其他方式跳过或默认允许。

总结

AI 的安全设计应该优先根据数据流设计,而不应该只基于提示词逻辑设计,因为 AI 不是完全可预测的传统程序。

但我们不能因噎废食。如今 LLM 能完成大量任务,正是因为它具备泛化能力和一定程度的不可预测性。

我们也不能时时刻刻紧盯 AI,因为 AI 是程序,行动速度远超人类。真正可行的方案,是把安全边界放到上下文、工具、网络、文件系统、权限、审计和用户授权这些可工程化的位置上。