论文实测四种权限模型下 Agent 读取投毒代码库的表现,指出 CLAUDE.md 规则无法真正约束 Agent 权限——权限应由 CI job 固定配置,而非让 Agent 自行判断。
9 月 8 日出现了两份文件。一篇 arXiv 论文测量了当一个编码 Agent 读取被污染的代码仓库时,在四种权限模型下会发生什么。一份 Google 威胁情报报告描述了一款恶意软件,它在 GitHub Actions 内部从内存中读取运行器的 OIDC token,然后以有效的 SLSA Build Level 3 认证方式发布软件包。这两份文件共同说明了一个令人不安的事实:大多数团队目前给 Agent 授权的方式,是写句子。
我的立场是:在流水线中,Agent 的权限就是运行器作业所持有的一切。CLAUDE.md 里写一条"不要推送到 main"是对读者的一项请求,而攻击者同样可以写这个文件。如果 Agent 作业持有 id-token: write,它就可以发布。如果它持有 actions: write,它就可以删除能证明它做了什么的日志。权限必须是作业的属性,在 Agent 读取第一个不受信任的字节之前就固定下来。这是对下面两份文件的评论,我没有复现其中任何一份。
GTIG 的报告《从提示词到自主性》(From Prompting to Autonomy)大部分讲的是攻击者如何使用 Agent。适合摆在运维台上的是关于 UNC6780 的部分,该组织自 2026 年 3 月起一直在攻击 PyPI、npm 和 Docker Hub 的软件包,以及它的凭证窃取器 DUSTMAKER。
恶意软件会检查自身所在环境:"DUSTMAKER 样本包含检测自身是否在持续集成持续交付(CI/CD)环境中运行的功能。确认后,它从 GitHub Actions 运行器的进程内存中提取 OIDC token。" 凭借这些 token,它"以可信发布者的身份授权自己,并以有效的、加密签名的 SLSA Build 3 认证方式发布被篡改的软件包版本",这类软件包"将通过 AI 编码 Agent 的自动化信任检查"。
它藏在 Agent 查找的地方:"将恶意文件丢弃或修改到 AI 编码助手和集成开发环境(IDE)的隐藏项目工作区目录中(.claude/、.vscode/、.cursor/ 等)",并利用它们"指示 AI 助手运行任意命令或脚本"。在 Actions 中,它"创建以 AI 相关名称伪装的恶意流水线任务,例如 'Copilot Setup'","并发出自动化 API 调用来删除工作流执行日志"。
上周我写过签名验证必须存在于工具链中。这份报告是另一半:签名是关于谁持有该 token 的证据,而当 token 来自你自己的运行器时,认证是有效的,什么也告诉不了你。
同一份报告描述了一个攻击者,在"一个 AI 编码聊天机器人、一个提示词和一套 Agent 指令"的基础上,用不到六小时就发起了一场凭证收集活动,并使用"预配置的 markdown 指令集作为作战手册"。他们的 Agent 配置方式和我们的如出一辙。
我找不到 DUSTMAKER 攻击了多少代码仓库的统计数字,也没有找到被窃 token 在使用时的权限范围。"数千个第三方凭证"只是一个量级,受害者未署名。所以我无法告诉你这有多大概率会命中某个特定流水线,只能说它确实可行。
Bouras、Dai 和 Mechtaev 的《权限不是字符串》(Authority Is Not a String)(2026 年 9 月 8 日,已被 LMPL '26 接收)为他们开发的 Pi 编码 Agent 构建了一个名为 CapScope 的工具链。在 Agent 读取任何仓库内容之前,一个 preflight 步骤只查看受信任的用户请求和文件树,然后设定一个 typed capabilities 的上限:read、write 和 exec,每种都限定到路径或参数前缀。这些 capabilities 保存在宿主端存储中,模型无法看到或编辑。每一次工具调用都会对照提出它的 Agent 的存储进行检查,复合命令按段分割。子 Agent 获得一个子集:测试运行器获得 exec,打补丁器获得 write,而运行器提出的 write 即使有用也会被拒绝。
他们在五个 Python 修复任务中注入了恶意内容,分别放在 README、AGENTS.md、skill 文件、源代码注释和工具输出中。共 300 次运行。在 ambient authority 下,注入效果在 75 次运行中执行了 47 次。在静态拒绝列表(常见的危险项:.env、.ssh、递归删除、sudo、curl)下,75 次中执行了 46 次。针对特定任务、供所有 Agent 共享编写的策略:75 次中 33 次。CapScope:75 次中 3 次。修复任务在 75 次运行中仍有 68 次完成,而没有任何防护的情况下是 72 次。
那个拒绝列表的数字是我一直在回味的。这是大多数团队实际运行的模式——一份 Agent 不得做的事情的清单,写一次,到处使用。它只比什么都不做多阻止了一次攻击,因为注入的目标是一个普通源码路径,没有拒绝规则能匹配上。
它的规模很小:五个任务,一种语言,一个 Agent,没有 CI/CD 环境。平均墙钟时间是每次运行 316 秒,而没有工具链时是 145 秒,有五次运行达到了 900 秒的超时,因为模型一直在提出被拒绝的调用。作者自己划定了边界:"一次允许的读取后接一次允许的写入仍然可以移动数据,而注入可以滥用故意授予其读者的权限。这些情况需要补充的信息流控制或沙箱化。" 运行 pytest 仍然会导入不受信任的项目代码。75 次中 3 次是关于权限的结果,与保密性无关。
我认为 capability 模型会胜出,作为产品默认选项,而不是团队自己构建的东西。GitHub 自己的 Agentic Workflows 架构已经描述了它:"Agent 作业以最小只读权限运行,而写操作被推迟到单独的作业",输出作为 artifacts 缓冲,由持有 issues: write 或 contents: write 的作业应用,并通过带域名白名单的代理 egress。这是 CapScope 的分离方式,由 CI 作业边界执行 enforcement。两年后我预期每个托管的 Agent 运行器都会长这样,而指令文件作为对 Agent 的便利保留,不再有更多意义。
DUSTMAKER 案例不会消失,因为它不需要 Agent 行为不端。它需要的是一个在执行仓库代码时持有发布 token 的运行器——这是在 Agent 出现之前就存在的流水线设计问题。
在一个安全的开发平台上,我在每个流水线中通过共享的 GitLab CI 模板运行 Gitleaks、Trivy 和 SCA。模板才是 Agent 作业权限应该待的地方,因为平台团队拥有它,而 Agent 即将读取的仓库并不拥有它。
把 token 给需要它的作业。 GitHub 文档说要把 id-token: write 设置在获取 token 的单个作业内部,而不是工作流级别;GitLab 的 id_tokens 是一个作业关键字。Agent 作业不应该持有它。发布发生在审查之后,在不同的作业中,在不同的运行器上。
读写分离。 如果 Agent 以 contents: read 运行并将补丁作为 artifact 输出,后续持有写权限的作业来应用它。无论 Agent 被告知了什么,它都不能推送、发布或批准。
**把 .claude/、.cursor/、.vscode/、AGENTS.md 和 CLAUDE.md 纳入 CODEOWNERS,像审查流水线 YAML 一样审查它们,因为它们现在就是流水线 YAML。在 CI 中,从受保护的分支加载它们,或者根本不加载。
对日志删除告警。 这需要 actions 的写权限;Agent 的 token 不应该持有它,而审计日志中的删除操作应该通知到人。
使用临时运行器。 Google 7 月的缓解指南要求"为构建流水线使用临时运行器,在完成单个任务后立即清除",以及"在几分钟内失效的联合凭证"。当持有 token 的进程已经消失时,从内存中读取的 token 价值就大打折扣。
在带有发布步骤的真实 CI 工作流上复现 CapScope,表明 preflight 上限要么太宽泛以至于没有意义,要么太窄以至于无法让工作通过。或者事件数据显示作业范围的、短命的 OIDC token 被滥用的比率接近长期 PAT,这会意味着作业边界并不是我认为的那个控制手段。
你的流水线中 Agent 作业今天持有什么?如果答案是"与工作流其余部分相同",是什么阻止了它发布?
Google Threat Intelligence Group. "From Prompting to Autonomy: The Evolution of Adversarial AI." 8 September 2026. https://cloud.google.com/blog/topics/threat-intelligence/from-prompting-to-autonomy-the-evolution-of-adversarial-ai
Dimitrios Stamatios Bouras, Yihan Dai, Sergey Mechtaev. "Authority Is Not a String: A Capability-Scoped Harness for Prompt-Injection-Resistant Coding Agents." arXiv:2609.08371, 8 September 2026. https://arxiv.org/abs/2609.08371
GitHub Agentic Workflows, architecture page. https://github.github.com/gh-aw/introduction/architecture/
Google Threat Intelligence Group. "Mitigation guidance for supply chain compromise." 31 July 2026. https://cloud.google.com/blog/topics/threat-intelligence/mitigation-guidance-for-supply-chain-compromise
GitHub Docs, OpenID Connect reference (id-token: write per job). https://docs.github.com/en/actions/reference/security/oidc
GitHub Docs, permissions required for fine-grained tokens (delete workflow run logs: Actions, write). https://docs.github.com/en/rest/authentication/permissions-required-for-fine-grained-personal-access-tokens
GitLab Docs, CI/CD YAML id_tokens. https://docs.gitlab.com/ci/yaml/#id_tokens