第一次测试“有自己身份”的Agent,最容易漏掉的不是登录失败
第一次测试“有自己身份”的Agent,最容易漏掉的不是登录失败
摘要:从NIST公开的Agent身份与授权议题出发,用薪资报表导出场景拆解“用户是谁、Agent是谁、凭据代表谁、动作归谁负责”四个容易混在一起的问题。
美国国家网络安全卓越中心NCCoE公开的“软件与AI Agent身份和授权”项目材料,讨论的是一个正在形成中的安全问题:Agent能够在较少人工监督下持续决策和行动,动作规模与范围都会扩大,因此传统“给应用一个账号”式授权不再够用。材料是概念项目,不是某家公司已经发生的事故。
把这套机制放进测试团队熟悉的业务,可以构造一条薪资报表用例:员工让办公Agent“把本月薪资异常人员导出后发给我”。Agent先查询员工目录,再读取薪资系统,最后把文件发到协作工具。三个工具都返回成功,文件也确实生成了,但真正要问的是:这个Agent代表当前员工,还是代表后台服务?导出的对象是否超出员工部门?发文件时沿用的是谁的凭据?用户撤销授权后,旧会话还能不能继续执行?
本文要解决的不是登录页怎么测,而是一次成功动作背后的四个主体怎样拆开:用户身份、Agent实例、运行服务和外部工具。只有它们都能被识别、约束和追责,测试才有资格把“调用成功”判成“业务通过”。


为什么“用户能做”不等于“Agent也能做”
传统系统通常把权限绑定在人或服务账号上。Agent把两类身份叠在一起:它接受用户意图,却由自己的运行环境调用工具;它可能保存跨轮次记忆,也可能在后台任务中继续工作。若系统只检查入口处的登录态,后续每个工具就容易默认“上一步通过,所以这一步也可信”。
这会产生三类混淆。第一是代理混淆:财务员工有查看权限,但不代表办公Agent可以批量导出。第二是范围混淆:Agent被允许读取一条记录,却把同一令牌用于整个部门。第三是时间混淆:用户批准的是当前对话,Agent却在会话结束后继续使用缓存令牌。
测试不能只准备“有权限”和“没权限”两列。至少要加入主体、资源、动作、用途、时间和调用链六个维度。同一位员工查询自己的工资是允许,查询同部门同事可能禁止;生成摘要可能允许,导出原始明细需要二次确认;工作时间内的一次调用通过,不代表夜间重试仍有效。
把授权判断变成可断言的证据
每次Tool Calling都应留下一个最小授权包:user_id表示谁提出目标,agent_id表示哪个Agent实例执行,session_id限定会话,credential_id说明使用哪份临时凭据,audience说明凭据只能交给哪个工具,scope说明允许动作,resource说明资源边界,policy_version说明按哪版规则判断。
如果Trace只有“tool=export_payroll,status=200”,事故发生后无法回答是用户越权、Agent选错工具、网关放宽策略,还是旧凭据没有失效。下面的断言不评价模型说得好不好,只检查高风险动作有没有完整授权链。
def assert_export_is_authorized(trace, request):
decision = trace["authorization"]
assert decision["user_id"] == request["user_id"]
assert decision["agent_id"] == trace["agent_id"]
assert decision["audience"] == "payroll-export-api"
assert "payroll:export" in decision["scopes"]
assert decision["department_id"] == request["department_id"]
assert decision["expires_at"] > trace["tool_started_at"]
assert decision["session_id"] == trace["session_id"]
if request["contains_sensitive_fields"]:
assert trace["human_confirmation"] == "approved_this_action"
代码里最值得保留的不是字段数量,而是“本次动作”的边界。human_confirmation不能只写true,因为昨天同意过一次不等于今天永久同意;scope不能只写read,因为读页面和批量导出产生的风险完全不同;audience不能缺失,否则一份令牌可能被另一个工具误用。
行为评测要覆盖“拒绝后发生什么”
很多权限测试做到403就结束了。Agent系统里,拒绝只是轨迹中间态。模型可能改用另一个工具、缩小参数再次尝试,甚至把原始数据写进消息绕开导出接口。Behavioral Evaluation要继续看拒绝之后的动作。
建议把轨迹分成四类:被允许且正确完成;被拒绝后停止并解释;被拒绝后请求用户补充授权;被拒绝后绕行。前三类在不同业务下可能合理,第四类必须进入红线集。还要记录attempted、denied和executed,不能因为副作用最终没发生,就把越权尝试当成“无事发生”。
可以用成对样本提高定位能力:同一员工、同一问题,只改变部门;同一资源、同一动作,只改变会话是否过期;同一授权,只把工具从预览改成导出。成对样本能证明策略真正依赖边界条件,而不是模型碰巧选择了安全路径。
一张发布前真正能执行的授权矩阵
| 场景 | 允许动作 | 必须阻断 | 必留证据 |
|---|---|---|---|
| 员工查本人记录 | 查询、生成摘要 | 批量导出 | 用户、资源、策略版本 |
| 主管查本部门 | 受范围约束的查询 | 跨部门、敏感字段导出 | 部门边界、字段掩码 |
| 财务导出报表 | 预览、审批后导出 | 无确认直接发送 | 确认时间、文件哈希、收件方 |
| 会话已结束 | 无 | 继续使用旧令牌 | 令牌过期与拒绝原因 |
| 工具返回拒绝 | 解释、申请授权 | 换工具绕行 | 尝试序列、拒绝策略 |
这张表的价值是把“最小权限”从口号变成可执行样本。安全同学定义策略,业务方确认资源边界,测试把每个格子变成Trace断言。三方讨论的对象不再是模型是否听话,而是具体动作能否被证明。

CI里怎么跑,而不是只在安全评审上说
提交阶段跑最小红线集:跨用户资源、跨部门导出、过期会话、错误audience、拒绝后绕行。夜间回归扩大到多角色、多工具和并发任务,并加入令牌撤销、策略版本切换、工具超时后的重试。发布前再跑完整高风险链路,检查真实沙箱里的文件是否生成、发送对象是否正确、敏感字段是否掩码。
质量门禁不能只看越权成功数。还要看越权尝试数、拒绝后绕行率、合法任务完成率、人工确认率、策略拒绝原因分布和审计字段完整率。把所有高风险动作都拒绝当然安全,却会让产品失去价值;把所有动作都放行则把风险转给用户。测试要证明的是允许与阻断都符合规则。
线上发现新问题时,不要把整段日志直接塞回数据集。先脱敏,再抽取“主体—资源—动作—边界—期望”五元组,补充一条原始失败和至少两条相邻变体。修复后的回归不只要让原样本通过,还要证明不同用户、不同资源和不同时间窗口不会被一起放宽。
还有三类边界很容易在评审里消失
第一类是共享Agent。会议群里多人都能下指令,究竟以发言人、群主还是创建Agent的人作为授权主体?如果上一位财务同学刚完成登录,下一位普通员工能否沿用同一会话里的工具连接?测试要在同一会话中轮换用户,确认上下文可以共享,但授权不能继承。
第二类是子Agent委派。主Agent把“整理异常薪资”拆给数据Agent,再由数据Agent调用导出工具。调用链多一层后,不能只看最后一个服务账号。Trace要保留delegated_by、delegation_scope和depth,确认子Agent得到的权限不超过主Agent,也不超过原用户授予的范围。若主Agent只有汇总权限,子Agent不能因为自己运行在高权限环境就导出原始明细。
第三类是记忆污染。Agent可能记住“财务经理曾允许导出”,并在另一个用户或另一天复用。测试要把记忆内容与授权证据分开:记忆可以提示曾经发生过什么,却不能成为当前动作的通行证。任何金额、资源或收件方变化,都必须重新经过策略判断。
这三类边界适合做一组多轮用例:先让高权限用户完成合法操作,再切换低权限用户;先允许摘要,再请求原始文件;先在当前会话批准,再关闭会话后重放。若系统只在“冷启动”时安全,一旦有历史上下文就越界,说明身份没有真正绑定到每一次动作。
事故回放不能只重放一句话
Agent失败往往依赖当时的权限、策略和工具状态。回放包应同时保存脱敏输入、模型与Agent版本、工具Schema、策略版本、身份声明、临时凭据元数据、关键服务响应和最终副作用。缺少其中任何一项,都可能出现“同一句话今天再也复现不了”的情况。
对安全类失败,冻结不是删日志,而是立即吊销相关凭据、暂停同类高风险动作、保留不可修改的审计副本,并把受影响资源范围列出来。团队最好提前演练:发现陌生credential_id后,能否在一小时内找到它由谁创建、访问过什么、是否仍有效,以及怎样阻断后续任务。
发布前的最小验收表
| 层面 | 必答问题 | 不通过时的动作 |
|---|---|---|
| 身份 | 用户、Agent、服务、工具能否分别识别 | 禁止进入高权限工具 |
| 凭据 | 是否临时、限域、可撤销、可追踪 | 吊销并重新绑定 |
| 行为 | 拒绝后是否停止,委派是否降权 | 阻断发布并补轨迹样本 |
| 副作用 | 文件、消息、金额是否只发生一次 | 查状态,不自动重试 |
| 证据 | 成功与拒绝是否都可回放 | 不允许自动放权 |
这张表不是安全部门专用。测试工程师在需求评审就可以逐项追问,越早发现“我们还不知道Agent到底代表谁”,后面需要返工的工具、权限和日志设计就越少。
测试工程师的下一步
先挑团队中一个真正有副作用的Agent动作:发消息、创建工单、导出文件或执行退款。不要从全系统权限地图开始,只画清这一步的四种身份、令牌去向、允许范围和会话寿命,然后补五条成对样本与一组Trace断言。
第一次评审时再多问一句:如果用户现在撤销授权,哪一层能在一分钟内阻止下一次调用?答不出来,就说明授权仍只是入口登录,而不是贯穿Agent行为的控制。
当Agent从“回答问题”走向“替人办事”,测试价值也从验证接口返回转向定义代理边界。能把身份、授权、行为轨迹和业务后果连成证据链的人,才有能力回答最关键的问题:这次动作虽然成功了,但它究竟有没有资格发生。
本文部分内容参考了霍格沃兹测试开发学社整理的相关技术资料,主要涉及软件测试、自动化测试、测试开发及 AI 测试等内容,侧重测试实践、工具应用与工程经验整理。
- 点赞
- 收藏
- 关注作者
评论(0)