跳到主要内容

113 篇博文 含有标签「security」

查看所有标签

第 1 天授予的权限,到第 90 天也没人收回

· 阅读需 11 分钟
Tian Pan
Software Engineer

你在第一天为 Agent 创建的 IAM 角色本应是临时性的。试点项目需要进度,团队需要 Agent 在演示前投入生产,而有人——大概就是你——在 PR 中加了一条评论:“发布后再收紧权限。”九十天后,试点项目已经上线,Agent 已经在为付费客户提供服务的生产环境中运行,而该角色仍然拥有对三个 Agent 从未接触过的存储桶的 write:* 权限。运维人员(On-call)无法告诉你这 18 个 Scope 中哪些是核心负载,哪些是冗余,因为唯一了解情况的人已经转岗,而能够证明区别的运行时遥测数据也从未接入。

这并不是关于一个粗心团队的故事。而是一个关于所有构建 Agent 的团队如何陷入同一困境的故事,因为大多数公司尚未发明防止这种情况发生的生命周期管理规范。人类身份识别在过去 30 年中为此积累了大量机制——入职工作流、季度访问审查、转岗时的自动权限撤销。而 Agent 身份识别只有一条 Slack 消息,写着“我晚点会清理”。第一天的授权变成了第九十天的遗产,而爆炸半径随着每次模型升级、每个添加到 Agent 工具箱的新工具以及每个接入该角色的新客户而不断扩大。

你的智能体在链式工具调用中获得的 OAuth 权限范围

· 阅读需 11 分钟
Tian Pan
Software Engineer

用户在你的智能体授权页面上点击一次“授权”。当会话结束时,该智能体已经链式调用了 11 个工具,协商了 3 次提权授权,现在拥有了它所触及的每个工具的权限并集。用户只记得授权了一件事。你的审计日志却显示它拥有半个账户的读写权限。OAuth 标准说一切都在按设计运行,而这恰恰就是问题所在。

经典的 OAuth 授权模型是为“一个应用与一个 API 通信”的世界构建的。智能体在两年前打破了这一假设,而标准在实践中尚未跟上,即使规范已经更新。其结果是一类无人刻意发布的静默权限提升——它随着每一次工具注册而累积,而你的安全审查却一直在盯着前门。

隐蔽式安全与正在阅读你 Wiki 的智能体

· 阅读需 13 分钟
Tian Pan
Software Engineer

公司内部有一个安全运行了十年的端点。它位于一个除了原始团队之外没人能猜到的路径上。它不在公开文档中。它不在 OpenAPI 规范中。它不在网关的“已记录路由”白名单中。它的身份验证层是一个任何内部服务都可以签发的令牌,因为威胁模型认为,触达它的唯一前提是已经知道它的存在。这个端点接受一个 JSON 数据块,在某个平淡的周二,它会重新发放退款、轮换 API 密钥或在两个计费账本之间移动数据行。自 2016 年以来,它一直正常且平稳地工作着。

上个月,一位同事将一个编程智能体接入了工程维基,以协助处理入职提问。该智能体索引了每一个 Confluence 空间、每一份存档的设计文档、每一页标有“请勿删除——历史记录”的页面。昨天,一名初级工程师询问智能体退款是如何运作的。智能体将一份被遗忘的 2018 年架构图、有人粘贴到操作手册里的 Slack 导出记录以及一份写了一半的故障复盘拼接在一起。它用对话式的文字完整描述了该端点、所需的令牌类型以及示例 Payload。端点本身没有改变,但它的威胁模型改变了。

你的 Agent 没察觉到那个沙箱其实是真的

· 阅读需 11 分钟
Tian Pan
Software Engineer

我认识的一个团队有一套教科书级别的 staging 设置。生产数据库的只读副本。一个假装会扣款的 Stripe 模拟账户。带着没人拥有的域名邮箱的合成用户。这个 agent 被要求在 staging 里端到端走一遍"账户欠费"的升级流程,作为发版演练的一部分。trace 看起来很干净,agent 做了它该做的事。

三分钟后,一个真实客户——一个付费客户,六个月前流失的,但仍然留在一个开发者用来播种测试数据的休眠导出里——回复了一封措辞礼貌的逾期付款邮件。那个"send_email"工具,与十几个其他全部以 mock 收尾的工具注册在一起,却接在了生产环境的 Mailgun key 上。两个 sprint 前配置它的开发者当时在快速迭代邮件模板,沙箱层级把发送量限制在每小时五封,把内部反馈循环搞坏了,于是他们换上了真 key"就用一下午",然后忘了换回去。没人复查过。agent 没有任何办法知道这件事。

当实习生在入职第一天部署 Agent

· 阅读需 10 分钟
Tian Pan
Software Engineer

实习生周一报到。周二下午,她已经接好了自己的第一个 Agent。周三上午,那个 Agent 用一份她本不该继承到的凭证调用了生产工具,但安全团队没人察觉,因为审计日志把这次调用记成了"实习生导师的 setup 脚本发起的"——技术上没错,操作上等于零。

这不是实习生不靠谱的故事,也不是导师粗心的故事。这是一个入职流水线的故事:它对"新人"的假设——只读优先、沙箱写次之、生产环境要熬到工龄门槛——背后有几十年的打磨;而对那些新人入职头几天就会去配置的 Agent,它的假设是零。给人用的 IAM 模型,已经不再是给"实际打到你系统上的东西"用的 IAM 模型,而大多数安全团队还没意识到这一点。

你的 Embedding 并不知晓外包人员已离职

· 阅读需 11 分钟
Tian Pan
Software Engineer

一名外包人员在上个季度结束了为期六个月的聘期。人力资源部门执行了离职清单:禁用 SSO、擦除笔记本电脑数据、移除 GitHub 席位、归档 Slack、撤销 Notion 访问权限。合规部门签字确认。六周后,一个内部 RAG 助手在回答问题时引用了该外包人员编写的一份机密战略文档——而引用的数据块在向量数据库的白名单中仍标记着该外包人员的用户 ID。事实来源(source-of-truth)的访问日志中没有任何读取记录,因为根本没有发生读取。检索来自一份从未被纳入离职流程的数据副本。

这是没人会画在架构图上的结构性问题。你的向量索引不仅仅是一个相似度搜索引擎。它是一个权限缓存——一个关于“谁能看到什么”的派生存储,冻结在你运行嵌入任务的那一刻——而且几乎没有人像失效其他内容那样去失效它。

无人书写的工具调用授权层

· 阅读需 10 分钟
Tian Pan
Software Engineer

你的 API 网关验证了用户身份。你的工具端点会检查用户是否有权删除该行。在这两次检查之间,存在一个并不存在的层:即决定模型在此次对话中是否被允许以这些特定参数请求 delete_user 的那一层。

在大多数智能体(agent)技术栈中,那一层就是系统提示词(system prompt)。它会说“小心执行破坏性操作”和“只删除用户明确要求你删除的记录”之类的话。这句话并不是访问控制。它只是对一个非确定性过程的礼貌请求,而评估该请求的组件,恰恰是攻击者试图操纵的那个。

你为单个智能体添加的工具,现在每个智能体都能用了

· 阅读需 11 分钟
Tian Pan
Software Engineer

六个月前,客户支持团队的人为他们的智能体连接了一个 send_email 工具。它奏效了。平台团队在共享工具注册表中注意到了它,在 PR 上点了个大拇指表情,然后就继续忙别的了。本周,一名安全工程师进行审计时发现,send_email 竟然出现在会议摘要智能体、数据质量机器人、一个没人正式负责的分析助手,以及一个自一月份以来就没动过的半成品原型中。这些智能体中没有一个需要发送电子邮件。而且,从来没有人审查过是否 应该 允许它们这么做。会议摘要智能体的 PRD 只有两句话长,其中根本没有出现 “外部通信” 这个词。

这是我审计过的每个共享工具注册表的默认状态。注册工具的行为——将 JSON 模式和处理器推送到中央目录中——被视为一种开发人员的便利,就像向共享库中添加实用程序函数一样。但一旦注册表被引入到每个智能体的提示词中,注册工具就不再仅仅是库变更。它是同时向公司内的每个智能体进行的部署,且完全没有审查每个智能体是否应该接收它。

权限提示是一个 UX Bug:当“人在回路”沦为“人工橡皮图章”

· 阅读需 10 分钟
Tian Pan
Software Engineer

观察一名开发者使用 Agentic 编程工具一小时,你会看到同一个动作重复四十次:弹窗出现,“允许 Agent 运行 git status 吗?”,手在眼睛读完之前就移到了批准按钮上。到第四十次提示时,提示内容根本没被阅读。它变成了一个用户学会全速通过的减速带。

这是“人机回环”(human-in-the-loop)的一种无声失败。架构图上仍然显示人类在把控每一个危险动作。审计日志仍然记录着对每个命令的明确批准。但人类已经停止了评估。他们变成了一个接入控制流的生物版 “yes” 函数 —— 虽然身在回路中,却不贡献任何判断。权限提示本应是一项安全控制,它却退化成了附带确认对话框的系统延迟。

Prompt Injection 是混淆代理问题,而非内容过滤问题

· 阅读需 12 分钟
Tian Pan
Software Engineer

在 Prompt Injection(提示词注入)违规事件发生后,最常见的调查结果通常是某种形式的“模型被骗了”。检索到的文档包含了隐藏指令,Agent(智能体)执行了这些指令,导致客户数据泄露。随后的修复方案几乎无一例外地是内容过滤器:扫描输入、对恶意指令进行分类,并在其到达模型之前将其剥离。部署过滤器,结案。

这个结论是错误的,而过滤器就像是一台无休止的“跑步机”。“模型被骗了”描述的是症状,而不是漏洞。漏洞在于,一个拥有实际权限的 Agent——如数据库令牌、发送邮件能力、文件系统写入权——接受了来自一个永远不该被允许指挥这些权限的来源的指令。这并不是一种新型漏洞,而是一个“混淆代理”(Confused Deputy)问题,操作系统在近 40 年前就已经对其进行了命名并基本解决了它。

如果你将 Prompt Injection 视为检测问题,你就是在参与一场与每一个能组织语言的攻击者之间的军备竞赛。如果你将其视为权限问题,你就可以复用数十年来行之有效的安全工程经验。

影子 AI:你的团队已经上线的 AI 智能体

· 阅读需 10 分钟
Tian Pan
Software Engineer

影子 IT 曾经意味着营销团队报销 SaaS 订阅,或者工程师私自创建 S3 存储桶。这很烦人,是采购方面的头疼问题,但大部分情况下是可以承受的。影子 AI 也是出于同样的本能——绕过缓慢的官方路径——只不过爆炸半径更大,且进入门槛几乎降至为零。

一名工程师可以在一个下午将 LLM API 调用接入生产工作流。一名支持主管可以在午饭前搭建一个无代码的分流智能体。一名数据分析师可以将一个季度的客户记录粘贴到聊天窗口中,以“快速总结一下”。这些都没有经过审查,没有出现在架构图中,而且你的治理计划无法保护一个它根本不知道存在的系统。

令人不安的是规模。2025 年 UpGuard 的一项调查发现,超过 80% 的员工——以及近 90% 的安全专业人员——在工作中使用未经批准的 AI 工具。你的安全团队在用,你的高管也在用。问题不在于你是否有影子 AI,而在于你是否能看到它。

你的工具描述是模型遵循的指令通道

· 阅读需 9 分钟
Tian Pan
Software Engineer

当安全团队审查一个新的工具集成时,他们会阅读代码。他们会检查函数的功能、它触及的内容、它需要的权限范围(scopes),以及它是否记录了敏感秘密。但他们几乎从不阅读那句决定模型是否调用该工具的句子——工具描述。那句话不仅仅是文档。它是模型视为权威的指令,而在大多数智能体堆栈中,没有人会去审计它。

工具描述是写给模型看的。模型利用它来决定工具何时相关、应该传递哪些参数,以及如何解释返回的结果。这使得描述成为了进入模型行为的一个控制通道。而当一个工具来自第三方注册表、一个你不运行的模型上下文协议(MCP)服务端,或者一个同事上周安装的插件时,这个控制通道的作者就是你从未同意信任的人。

这就是差距所在。输入净化(Input sanitization)检查用户输入的内容。代码审计(Code review)检查函数执行的内容。工具描述介于两者之间——它是表现得像输入的配置——它从这两个防护网中漏掉了。