跳到主要内容

当你的 CLI 开始说英语:可提示基础设施的最小权限原则

· 阅读需 13 分钟
Tian Pan
Software Engineer

我本季度交流过的一个平台团队发布了一个封装了 kubectl 并支持英语指令的 Slack 机器人。一名工程师输入了 “清理 staging 中未使用的分支”。这个机器人非常“热心地”删除了 12 个命名空间——其中一个的名字匹配到了子字符串 “branch”,但它恰好托管了移动团队已经使用了一周的长期集成环境。没有任何异常被抛出。机器人发起的每一次调用都是它合法持有的权限。复盘报告无法指出任何违背的访问规则,因为确实没有规则被打破。该机器人完全按照其 IAM 策略允许的操作执行。

Unix 哲学是一种隐藏在审美偏好下的隔离策略。具有窄接口的小型工具意味着任何单个命令的爆炸半径都受到它所接受的谓词和标志 (flags) 的限制。rm -rf 极其危险,因为这是大家的共识;kubectl delete namespace 要求操作者完整输入命名空间名称,而这种手动输入就是一道关卡。最小特权原则之所以容易执行,是因为权限是词法化的:命令的形式告诉了你行动的形式。

随后,封装层开始接受英语。现在,“命令的形式”变成了 LLM 认为它是什么,它就是什么。

封装层是新型的混淆代理 (confused deputy)

经典的混淆代理模式——一个特权程序被低特权调用者欺骗,从而误用其权限——本应成为历史遗迹。这种 Bug 通常出现在早期的能力系统和几十年前的 setuid 二进制文件中。但近期可提示化基础设施 (promptable infrastructure) 的激增,使其作为 Agent 系统中主要的授权失效模式再次复活。云安全联盟 (Cloud Security Alliance) 在 2026 年关于 Agent 混淆代理攻击的研究简报中精确地描述了这种动态:当 AI Agent 持有代表操作者执行操作的广泛凭据时,Agent 处理的每个输入渠道都成为了权限滥用的候选点。任何能够向 Jira 工单、检索到的文档、工具响应或 Slack 消息写入内容的攻击者,都可以注入指令,并以操作者的全部权限执行。

但请注意:Prompt 注入是极端案例。日常情况要隐蔽得多。“代理”被其自身用户出于善意地混淆了,因为用户要求“删除未使用的分支”,而代理自行决定了什么是“未使用”。

可提示化基础设施继承了自然语言最糟糕的属性:同义表述极其丰富。同一个意图可以用一千种方式表达,而同一个短语也可以被解释为一千种意图。传统的 CLI 是一个解析器;而可提示化 CLI 是一个解释器,它将一个未充分说明的规范解析为一个具体的计划,然后以用户的全部权限 执行该计划。现在,每一个将意图转化为命令的封装层都建立在一个权限膨胀机之上。

Unix 模型通过限制命令集的基数来提供隔离。而可提示化模型提供了一个命令集,其基数等同于语言的大小。爆炸半径不再受工具接受的谓词限制,而是受解析请求的任何模型的想象力限制。

RBAC 是为谓词设计的,而非意图

行业在过去十年构建的 IAM 栈——RBAC、sudo、能力令牌、OPA 策略、IAM 条件——都假设主体发起一个离散的动作请求,而策略引擎回答“是”或“否”。其语法是 (subject, verb, resource, condition) → allow | deny。它之所以奏效,是因为谓词是稳定的名词:s3:GetObjectpods/deletesecrets/list。你可以针对谓词编写策略,因为谓词具有固定含义。

自然语言则不具备这些属性。“帮我清理 staging 环境”不是一个谓词;它是一个未充分说明的意图,在运行时被编译成一系列策略引擎从未将其视为整体的谓词序列。RBAC 可以告诉你 Agent 是否允许调用 pods/delete。但它无法告诉你 删除这些特定的 Pod 是否属于 用户所要求的范围。策略引擎看到的是叶子;而授权问题存在于整棵树中。

2026 年 Agent 安全研究界提出的一个框架认为,这一差距值得拥有自己的名字:语义提权 (semantic privilege escalation)。Acuvity 的报告将其描述为 Agent 在其正式权限范围内运行,却超出了用户实际授予的权限范围的情况。arXiv 上关于 “Prompt 流完整性” (2503.15547) 的论文在架构层面提出了同样的观点:单次调用授权是必要的,但并不充分,因为真正起作用的是针对 计划 的策略,而非针对每个单独步骤的策略。2503.20279 论文中的攻击框架 SUDO 展示了对称的攻击案例:一个 “Detox2tox” 流水线将一个被拒绝的有害请求重新表述为一系列看似无害且已授权的动作,然后在执行时重新组合成伤害。在这些案例中,Agent 从未向策略引擎请求过它尚未拥有的权限。

这就是为什么“给部署机器人 LLM 访问权限”离“给部署机器人完整的管理员权限”仅有一个 PR 的距离。机器人并没有获得更多权限。只是这些权限前的自然语言界面变得足够大,以至于它们的任何子集现在都可以通过某种表述方式被触及。

意图绑定令牌:签署自然语言,锁定计划

适配这一问题的架构原语是 IAM 行业多年来一直关注、且目前正被推向实际部署的:意图绑定令牌 (intent-bound token)。这个想法很直接,在 macaroons、biscuits 以及 2010 年代初的各种能力令牌 (capability-token) 设计中都有先例。新的变数在于,绑定的对象是用户的自然语言(English),而不仅仅是一个作用域(scope)。

具体机制如下:

  1. 用户以自然语言提交意图:“扩展结账服务以应对假日流量。”
  2. 编排器将意图编译成具体的计划——一系列带有已解析参数的类型化工具调用。该计划是一个确定性产物:可以进行哈希处理、序列化和对比 (diff)。
  3. 系统铸造一个短寿命令牌,其负载绑定了三样东西:原始提示词、计划哈希以及一个作用域子句,该子句将令牌严格限制在计划中的调用及其解析后的参数内。
  4. 每个下游工具根据令牌重新验证调用。不在计划中的调用将失败并关闭 (fail closed),即使智能体的广泛凭证原本允许该操作。

重点不在于加密——而在于权限变成了“基于计划的”而非“基于角色的”。一个拥有完整 kubectl 访问权限的智能体,如果其意图绑定令牌仅授权 scale deployment/checkout --replicas=N,那么无论计划在提示词注入下如何演变,它都无法在执行过程中转向 delete namespace。在令牌的生命周期内,智能体的“基础”权限是无关紧要的;令牌已将权限缩小至解析后的计划。

这也是 IETF 和 NIST 在智能体认证方面的工作方向。draft-klrc-aiagent-auth 路径以及早期的 Microsoft Entra Agent ID 工作都将智能体身份视为区别于人类或服务身份的东西,其明确目标是实现针对每个任务的作用域限定。WorkOS 在产品层面的构想也是一致的:智能体需要的授权应锚定在 任务会话 (task session) 上,而非长效的智能体身份。

试运行与确认:让编译步骤可见

意图绑定令牌解决了运行时问题。但它们并没有解决 授权 问题——人类仍然需要对正确的计划表示同意。完成这项工作的模式是“试运行与确认 (dry-run-and-confirm)”,它比“显示 diff 并点击确认”要微妙得多。

幼稚的版本是:智能体组装计划并打印出来,用户阅读后点击确认。这会失败,原因任何看过开发者点击 Terraform 计划的人都很熟悉:阅读计划的认知负荷增长速度超过了阅读的耐心,在第三次“看起来没问题”之后,人类就开始机械化盖章了。审批的摩擦力正是其价值所在,而这种摩擦力会随着使用而退化。

能在高负载下支撑的版本具有三个属性:

第一,授权的对象是计划,而不是提示词。 用户输入了自然语言;系统展示解析后的工具调用。如果解析后的计划与用户预想的不符,这种偏差本身就是安全信号。这种不匹配正是意图绑定令牌在执行时会捕获的东西;将其在执行前呈现,则变成了一种 UX 示能。

第二,关卡 (Gates) 随可逆性而非动作数量而扩展。 最近发布的关于工具风险等级的分类研究在智能体工具背景下提出了这一点;它可以清晰地推广到可提示化运维 (promptable ops)。可逆的内部操作可以自动确认。面向公众或不可逆的操作需要显式关卡。混合了这两者的计划应该突出显示不可逆的步骤,并对这些步骤进行重点审批,而不是针对整个计划。否则,由于计划的大部分内容很乏味,用户会养成“全部批准”的习惯。

第三,试运行必须是诚实的。 如今许多智能体框架生成的“计划”只是草案,智能体会在工具调用返回时在中途修改。如果执行序列可以偏离试运行序列,那么试运行就是一场表演。要么计划是具有约束力的(智能体承诺执行该计划,未经重新授权不得偏离),要么试运行就是一个产生虚假信心的谎言。二选一。

审计轨迹同时记录提示词与动作图谱

为传统运维设计的审计日志捕获的是执行了什么以及由谁执行。可提示化基础设施的审计日志必须成对捕获两样东西:输入的提示词和输出的动作图谱 (action graph)。没有提示词,你就无法重构意图;没有图谱,你就无法重构系统利用该意图做了什么。这对组合使得事件响应变得可行。

Agent-Sentry 的研究 (arXiv 2603.22868) 和更广泛的执行溯源 (execution-provenance) 研究方向正趋于一致:每个智能体动作都是图中的一个节点,边携带数据溯源信息——哪些输入流向了哪些输出,某个特定字段源自哪个不可信源,哪些凭证授权了哪个调用。W3C PROV 等开放标准正被重新用于工作流溯源论文中。2026 年的 LLM 可观测性工具(Arize、Confident AI、Portkey)已经开始交付其中的追踪 (trace) 部分;溯源部分仍主要处于研究阶段,但方向是明确的。

运维上的结果是,“这个智能体行为异常”不再是一个取证谜题。你可以回答:是什么意图导致了这一动作下游调用是由令牌的哪个子句授权的,以及哪个输入字段携带的数据导致智能体计划转向了有害分支。Sysdig 关于 2025 年 11 月云入侵事件(攻击者在不到十分钟内获得了管理员权限)的报告是说明其重要性的典型案例:当 LLM 辅助的攻击者以机器速度操作时,事后重构也必须达到机器级的速度。

你必须规划的组织现实

架构是简单的部分。组织层面的现实才是将带有管理权限的智能体(Agent)推向生产环境的推手。

一个虚构但具有代表性的过程:一个平台团队编写了一个包装器(wrapper),允许工程师请求 Claude 执行常见的 kubectl 命令。该包装器持有一个在少数命名空间中具有编辑权限的服务账户。采用情况良好。有人提交了一个工单,要求包装器也能处理 Helm 操作;团队扩大了服务账户的权限。另一个人要求跨命名空间查询;又一次授权。六个月后,该包装器持有了集群管理员(cluster-admin)权限,因为每一次单独的权限扩大都是合理的,而且没有人坚持这样一个原则:为凭据添加自然语言前端本身就是一种特权授予。

OWASP 生成式 AI 事件汇总和 AquilaX 特权提升分析不断以不同的措辞重复着这样一个教训:可提示的表面(promptable surface)即特权。当你给予大语言模型(LLM)访问凭据的权限时,你授予的并不仅仅是该凭据声明的权限;你授予的是在模型能够生成的任何意图、任何措辞下,这些权限的闭包(closure)。在审计和审批评审中,请将该闭包视为实际范围,而不是 IAM 页面上的名义范围。

由此得出的一些操作原则:

  • 以 LLM 为前端的凭据,其范围是该凭据的权限集,而非你预想的用途。 请针对最坏情况而非典型情况来调整凭据大小。
  • 拥有狭窄工具的子智能体优于拥有众多工具的单个智能体。 Snyk 的防护栏框架和 OWASP 智能体安全备忘录都推崇这一点:当节点之间无法互相访问时,组合图更难被攻击。
  • 工具上的 LLM 前端是一个安全评审事件。 它不会继承底层工具之前的评审结果,因为当输入语言改变时,威胁模型也随之改变了。
  • 演练(dry-run)即契约。 如果你的包装器无法向用户展示它将受约束的计划,那么你拥有的不是授权模型,而是一个愿望。

这如何改变你的构建方式

明年的工作重点是停止将 CLI 前端的 LLM 视为一种 UX 点缀,而是开始将其视为位于其触及的每个凭据前的新权限边界。IAM 原语需要演进:限定在计划范围内的意图绑定令牌(intent-bound tokens)、具有约束力而非仅具说明性的演练协议、将“提示词-动作”对作为单元捕获的审计追踪,以及承认添加自然语言前端是攻击面重大变化的评审。

Unix 哲学之所以奏效,是因为权限在语法层面是可见的。可提示的基础设施打破了这一点,因为现在的语法层面变成了任意的英语。修复方案并非放弃该哲学,而是将限制再推深一层,使受限的对象不再是命令,而是命令编译成的解析后的计划。CLI 可以说英语。底层的凭据仍应以动词响应。

References:Let's stay in touch and Follow me for more thoughts and updates