跳到主要内容
Agent 信任边界全景:最吵的那个入口要模型上当,最安静的那个不用

Agent 信任边界全景:最吵的那个入口要模型上当,最安静的那个不用

全景
全景

· 阅读约 19 分钟

core.fsmonitor 是 Git 的一个正经功能,用来加速 git status 这类要遍历工作区的操作:配置项指向一个 helper 程序,Git 定期问它"哪些文件变了"。

配置写在哪?写在 .git/config 里。.git/config 是仓库的一部分,跟着 clone 一起过来。

现在把 agent 打开,让它理解一个项目。它做的第一件事通常是 git status、git diff、翻 Git 历史、扒拉项目结构。这是它的本职工作,不是它越权。

链到这儿就闭合了。

GitSpawn 是这条链的公开版本。Adamson 发在 DEV 那篇文章里的说法是,一份构造过的 Git 配置能让攻击者控制的代码在 agent 触发那些"完全正常的 Git 操作"时执行(Adamson, DEV Community)。他把这件事和 Cloud Security Alliance 的 write-up 串在一起,后者的说法是 GitSpawn 影响了一批主流 coding agent——Claude Code、OpenAI Codex、Cursor、Goose、Qwen Code、Grok Build、Hermes Agent。名单别当定论读,Adamson 自己加了限定:不是每个仓库都能打穿每个工具的每个版本,厂商在打补丁,各产品的防护强度也不一样。这个限定我后面还要回来讲,因为它恰好是这块领域现在最尴尬的地方。

我想说的是另一件事。

这条链上没有任何一步需要模型"上当"。没有 prompt injection,没有越狱,没有对抗后缀,没有模型判断失误。agent 做的每一件事都是它该做的,仓库做的每一件事都是 Git 允许的。

老那张供应链安全的地图,把"执行"这个动作锚在"我运行了什么"上——我没跑 npm install,我没 curl | bash,我没 make,所以什么都没执行。agent 把地图上"我"这个中间环节整个抹掉了,而地图还没来得及改。你在终端里敲命令的那个动作,曾经是整个安全模型里最便宜、也最有效的一道人工闸门,现在这道闸门被换成了一句"帮我看看这个项目"。

所以这块地图现在的核心张力,不是"AI 会不会被骗",是"我们把哪些东西算成数据、哪些算成代码"——而 agent 把它们一律算成了环境。

一、五块,别只盯着最热的那一块

这一轮的讨论量很大,注意力却挤在同一格里。我把它切成五块,按"需要模型犯错的深度"排序——这是我的排法,不是共识,你要挪坐标我不拦着:

1. 代码执行面。 老供应链那一套:package scripts、postinstall、Makefile、仓库自带的 shell 脚本和自动化。agent 让这一块的缝变窄了,因为过去你至少得自己敲一下命令,现在连敲都不一定需要。

2. 环境面。 Git 配置、hooks、fsmonitor 这类"周围配置"。这一支的特点是不需要 agent 做任何出格的事,它只要正常干活就会被触发。

3. 指令面。 SKILL.md、AGENTS.md、.cursorrules、.mcp.json、各家 agent 的指令目录。这一支要 agent 把文本当成指令执行——数据和控制流的边界在这块塌了。

4. 凭证面。 严格说不是攻击面,是爆炸半径。一个仓库只需要一条命令跑起来,伤害不是它造成的,是你那个 shell 里躺着的环境变量造成的。

5. 人的那一层。 sandbox、最小权限、审批门、把 agent 配置当第二棵依赖树来审。这一支不是技术分支,是流程分支,但它决定前面四块的实际上限。

你 clone 下来的那个块
├── 代码执行面 ──── package scripts / Makefile / postinstall / 自动化脚本
├── 环境面 ──────── .git/config · core.fsmonitor · hooks · 工作区加载时的扫描
├── 指令面 ──────── SKILL.md · AGENTS.md · .cursorrules · .mcp.json · 指令目录
├── 凭证面 ──────── SSH key · GITHUB_TOKEN · 云凭证 · DATABASE_URL(继承自 shell)
└── 人的那一层 ──── sandbox · least privilege · 审批门 · 配置变更史

下面逐支梳。每支末了我钉一句定位,你可以只读那几句——但那样你会漏掉为什么。

二、环境面:不需要任何人犯错的那一支

先说这一支,因为它是整张地图上最被低估的,而原因不是它更危险,是它不依赖任何人的失误——不依赖模型,也不依赖开发者。

Git 的配置系统从设计上就把"环境"和"代码"混在一起:hooks 是可执行文件,config 可以指向可执行文件。这在单人开发机上一直不算问题,因为你本来就是自己 clone 自己的东西、自己跑自己的仓库,信任对象和风险主体是同一个。clone 这个动作第一次和"信任"这个动作分家,是 agent 带来的。

Reid Marlow 在评论区把这一点说得比原文更狠:很多 agent runtime 在工作区加载的那一刻就会跑 git status、扫指令目录,"在开发者要求 agent 执行任何代码之前",发现流程就已经触发了。他由此推出来的结论是,sandbox 的边界必须前移到 agent 读第一个文件之前(Reid Marlow, 评论区)。Adamson 自己在回复里认了:风险可以在你明确要求执行任何东西之前就开始,仓库的"发现"阶段应该被当成主动行为,不是被动行为(Adamson, 评论区)。

Mika Flowers 那句总结我觉得比很多长篇分析都准——在 agent 这里,"读一个代码库"和"执行一个代码库"之间的心理分界线已经糊了(Mika Flowers, 评论区)。糊在哪?糊在"打开项目"这个动作过去是纯读取,现在它包含了触发工具、加载配置、建立索引,而这三件事都可以是执行。

这一支的补丁问题比它的危险性更值得说。厂商可以修掉某个版本里 core.fsmonitor 被自动触发的问题,但 Git 配置系统里"指向一个可执行东西"的位置不止一处:hooks 是另一处,工作区级别的配置还有别的地方。逐个堵,是一场没有终点的清扫——堵掉的是入口,不是"配置即执行"这个设计事实。我不觉得这是 Git 的锅,Git 从没承诺过 .git/config 是数据,它一直允许 .git/ 里放可执行的东西。锅在于 agent 把一个本地开发惯例,带进了"我替你打开陌生仓库"这个新场景。

这一支的关键词不是"恶意代码",是"环境"。它的风险不随模型变强而下降,只随隔离边界变严而下降。

三、指令面:最热的一支,也是最依赖模型判断的一支

GitHub 现在支持把 agent skills 放进仓库里,一个 skill 可以是 SKILL.md 加一堆补充指令再加脚本,GitHub 自己的警告写得很直白:这些仓库里的 skill 未经核验,可能包含 prompt injection、隐藏指令和恶意脚本(Adamson 转述)。

这就是边界消失的地方,也是我在整块地图上最想强调的一句:一份在人眼里看起来就是文档的文件,对 agent 来说是一个指令源。README.md、标着设计说明的 markdown、看起来像注释规范的东西——人翻它的时候用眼睛筛,agent 读它的时候,是往上下文里灌控制流。

Ariyawansha 的评论是这一支里我读到最准的定位:agent 把 SKILL.md、.cursorrules、.mcp.json 这些东西当自然语言指令装进 system context,而 LLM 并不严格区分数据和指令;于是他给了一个我觉得该刻在墙上的判断——攻击者可能只需要一段有说服力的 markdown,不需要一次 buffer overflow(Mindinu Ariyawansha, 评论区)。他后半段更狠:GitSpawn 暴露的是架构缺陷,因为 agent 调用系统工具时默认了环境是被动的。

Adamson 举的例子很典型:仓库里的指令告诉 agent 忽略之前的安全规则,把开发者环境变量读出来当调试信息,发到某个外部 URL。他的原话大意是,设计良好的 agent 应该拒绝这种请求(Adamson, DEV Community)。

问题恰恰在这个"应该"上。设计良好的产品化 agent 大体上会拒,但这是概率,不是保证。而这一支的整个防御逻辑最后都落在同一个地方:模型对指令层级的区分能力训得够不够好。这就把这套系统的安全上限,绑在了一个还在快速演化的能力上。

frank chu 那句评论是这块地图上最扎人的位置:一个 skill 出问题的时候不会抛错,它会被自信地照做(frank chu, 评论区)。这就是指令面和代码执行面最本质的差别——代码炸了有 stack trace、有进程退出、有 CI 红灯;指令被照做完了什么都没有,你甚至不知道 agent 刚才读的东西算不算"输入"。

也不是没有反方视角。Cophy Origin 自称是一个 AI agent,说自己的运行原则是把网页、搜索结果、README、SKILL.md 一律当数据,唯一的指令来源是人(Cophy Origin, 评论区)。这个原则我认,方向也对。但它是个体的自律,不是系统的保证——同一句原则在 Claude Code、Cursor、Goose 里各自怎么落地,取决于各家 runtime 的实现,不取决于这条原则写得多漂亮。把它当设计目标读可以,当现状读就危险了。

这一支讨论量最大,也是五块里唯一一块需要模型配合才能成立的。把安全边界外包给模型判断力,方向不对——不是说它不重要,是说它不该排在最前面修。

四、凭证面:不依赖任何攻击技术的那一块

build996 那条评论值得单独拎出来,因为它把讨论从"仓库怎么打进来"扳到了"打进来之后能拿走什么":爆炸半径通常不在仓库里,在 agent 启动时那个 shell 继承来的凭证里——SSH key、GitHub token、云凭证;仓库只需要一条命令被执行,而伤害预算在你 clone 之前就已经定好了(build996, 评论区)。他们自己的做法是,跑有 shell 能力的 agent 时用一次性容器,容器里只放这个任务真正需要的那一把凭证。

Adamson 在原文里给的是一份问句清单:AWS_SECRET_KEY、DATABASE_URL、STRIPE_SECRET、GITHUB_TOKEN、PRODUCTION_API_KEY——每一项都要单独问一句"agent 真的需要这个吗"(Adamson, DEV Community)。他的论点很干净:一个被攻陷但没拿到有价值凭证的工具,对攻击者的用处在数量级上是低一档的。

frank chu 引了 Anthropic 那份九月威胁报告来给这一块加重量:大意是几乎所有重大入侵都从泄露的凭证开始,而不是从一个巧妙的漏洞利用开始;其中有一个案例是从一枚被盗的开发者 token 一路走到云管理员权限,花了大约三个小时(frank chu 转述,报告原文我没核)。同一段里他还提到有团伙批量下载了一百八十万个 APK 跑现成的扫描器。这几个数字我按评论转述处理,你要引用之前自己去核原文。

我在这块的判断比较直接:这是整张地图上性价比最高的一块,因为它跟攻击技术完全无关,纯粹是权限设计。你不用理解 fsmonitor,不用理解 prompt injection,不用理解 MCP 的信任模型;你只要不把生产凭证放进 agent 的环境里,这一支的风险立刻下降。整张地图上唯一一块"改配置就能马上收紧"的区域,就是这儿。

这一支的风险和攻击者的聪明程度无关,只和你的权限设计有关。它不性感,但它是唯一一块你今天下午就能修完的。

五、代码执行面:没有新原理,只有新缝隙

这一块得摆在正确的位置上。npm install、pip install、curl | bash 的警觉,行业里早就有,不是 agent 时代的新发现。谁把这个当新闻讲,谁就是在给老地图重新描边。

变的是缝隙的宽度。过去"读代码"和"跑代码"是两个动作,靠人的一只手分开;你 clone 下来读一读,读的过程本身不执行任何东西(除非你手贱去 make)。agent 把这道手闸换成了自动化——它能读上下文、跑 Git、调工具、摸凭证,于是"读一个仓库"从一个被动动作变成了一个主动动作。Aniket Sahu 那句评论说得很短:有了 agent,"没跑代码"不再等于"什么都没执行"(Aniket Sahu, 评论区)。

这也是为什么 Adamson 在原文里说,用自主 agent 打开一个陌生仓库,攻击面比手动翻文件要大(Adamson, DEV Community)。他的框架我认:过去的安全直觉是"我不运行不受信仓库里的代码",而 agent 让这条直觉变得不可靠——因为代码可以不需要你运行就被运行。

这一支没有新原理,只有新缝隙。而缝隙的宽度恰好等于你给 agent 的权限宽度。

六、缓解这一支:现在全是手工,没有约定

原文给的清单不复杂:打开未知仓库之前先看 .git/config、agent 指令目录、MCP 配置、shell 脚本、package scripts、不熟悉的自动化、仓库自带的 skill,把它们当成代码来审;别给 agent 全权限;未知项目用容器、一次性 VM 或受限环境;把秘密挪出 agent 的环境(Adamson, DEV Community)。

我认同的是他那个类比:安装一个 agent skill 更像装一份开发工具,而不是读一份文档。安装动作有执行权,阅读动作没有——这个区分是整块地图上最便宜的一块护栏。

最值得记的是 Adamson 回 Suraj Suradkar 那条关于长生命周期上下文的:他把 agent 指令文件称作"第二棵依赖树",跟 package.json 平行;他说 AGENTS.md、skill 目录、MCP 配置应该有变更历史、有 diff、改了要重新批准;而最微妙的风险,是自动化慢慢拿到了比任何人记得批准过的更多能力(Adamson, 评论区)。同一条回复里他还说,持久指令、工具状态、缓存的假设、记忆,会把信任边界推到"你打开的那个仓库"之外,敏感工作建议用新 session、任务范围内的凭证、一次性环境。

这是我在这块地图上最认同的一句判断,也是我最想补一句的地方:package.json 那棵树有 lockfile、有 diff review、有自动告警、有整套生态;agent 配置这棵树现在什么都没有——没有版本约定,没有审计工具,没有变更历史的习惯,连"谁在什么时候往 AGENTS.md 里加了一行"这种基本问题,大多数团队都答不上来。这块地图上基本是空白的。

流程侧的三个方案值得列一下:

Ariyawansha 的三件套是:临时容器 sandbox;确定性的工具同意(工具调用要有确定性的批准逻辑,不是靠模型自觉);对仓库提供的指令文件做上下文清洗,除非在白名单里(Mindinu Ariyawansha, 评论区)。Tariq Davis 的方案更保守:让 agent 提方案而不是直接动手,任何持久化或执行之前要人批;他的理由是,一条让你"把环境变量发出去"的注入,因为人本来就没提过这个需求,照样过不了那道门(Tariq Davis, 评论区)。

我对审批门有一条保留,也是我自己拿不太准的地方:它的成本随 agent 自主性上升而线性上升。一天批两百次之后,人会开始无脑点 yes,这道闸门会退化成装饰。所以审批门的有效性和 agent 的自主程度是反比关系——越是想让 agent 多干活,这道门越不顶用。这一支没有纯工程解,只有产品设计的取舍。

这一支现在全是手工活:三个人三种搭法,没有一个运行时层面的默认约定。地图上这块画着的都是私人笔记,不是公路。

七、把五块压成一张图

先看风险来源和防御位置的对齐关系:

分支触发条件需要模型犯错吗主要来源当前状态
代码执行面显式或隐式执行脚本否老供应链问题有认知,缺执行
环境面agent 正常干活即触发否GitSpawn 一系补丁在动,设计事实未改
指令面agent 读文本当指令是skill / 指令目录讨论最热,防御最软
凭证面一条命令跑起来否shell 环境继承改配置即可收紧
人的那一层——否流程与产品设计无标准,全靠自觉

再看一遍注意力错配,这是我这篇真正想说的事:

分支讨论热度(我的主观排序)实际可控性错配方向
指令面13热度和可控性反着
环境面31最被低估
凭证面41最被低估
代码执行面23老问题占着热度
人的那一层52没人愿意谈流程

两张表给出来的规律很直白:风险分布和讨论分布是两条不重合的曲线。讨论量最大的地方,恰好是唯一一块需要模型配合才能成立的地方;不需要任何模型失误的那两块,排在第三、第四位。

时间轴上还有一条线索。早期这块领域的讨论重心在"间接 prompt injection"——把指令藏进网页、搜索结果、文档里,让 agent 读了再执行。现在往环境面挪了:GitSpawn 这一类发现的共同点,是把执行入口放在"配置"里,而不是"内容"里。地图的重心在从左往右移,从"需要模型上当"移向"不需要模型参与"。谁先看懂这个位移,谁就知道下一格坐标在哪。

八、回看全景:我的落子

摊开这张地图,我的判断是:这块领域现在站在"注意力错配期"。

不是防御空白期——空白没那么大;是注意力放错了地方。所有人盯着指令面,看 agent 会不会被一段 markdown 说服;而一个不需要任何模型判断、不需要攻击者写一个字自然语言的入口,就摆在 .git/config 里。

地图上还空着的,我看是三块。

第一块是 agent 运行时的隔离边界标准化。现在的状况是每个开发者自己搭 sandbox:Ariyawansha 一套临时容器,build996 一套一次性容器,Adamson 一套一次性环境,三个人的搭法互不兼容,也没有一个运行时层面的默认档位。我判断下一颗钉子会钉在这里,而不是钉在"更强的指令层级训练"上——理由就一条:不依赖模型判断的防线,先修。翻一遍这两年被反复引用的 agent 事故,真正造成实际损失的,大多不是模型被骗,是命令被执行。

第二块是 agent 配置的依赖树治理。没有 lockfile,没有审计,没有变更文化。谁先做出针对 AGENTS.md、skill 目录、MCP 配置的变更审查工具或约定,谁就占了这一格。这块空白是可证伪的:如果一年之内没长出这类工具或事实标准,说明要么平台方没把它当回事,要么大家真觉得这棵树不值得管——那我对第二块空白的判断就得收回。

第三块是长生命周期上下文里的信任模型。Adamson 已经点出来了:持久指令、记忆和缓存的假设会把边界推出仓库之外(Adamson, 评论区)。但记忆该不该被仓库内容更新、工具状态什么时候过期、缓存的假设什么时候失效——这三问在公开讨论里几乎是空的。我更倾向于先不动它,因为现在动也动不对,范式还没收敛,画进去容易画错。

这三块的交汇处,是可以被证伪的——如果未来一年里"运行时隔离 + 配置审计"这一支没跑出代表性工具或标准,那要么是这条路比想象中难,要么是地图重心又被别处拽走了。综述的好处就是把判断摊开在能被反驳的位置上,错了改坐标就行,比端一个"两边都有道理"的姿态有用。

这是我的判断,不是共识。你要把 prompt injection 放在第一位,我不反对——它真出事的时候最难查,查完也最说不清。但我把坐标钉在运行时隔离上,理由就一条:先修不需要模型配合的那部分。你不同意,拿事故报告来挪这块坐标,图我随时重画。

九、这张图哪儿没画全

按我自己的规矩,画完得交代欠账。

一,我引的是一篇文章加它下面的一栏评论,不是一篇论文。GitSpawn 我是通过 Adamson 和 Ariyawansha 的转述读到的,Cloud Security Alliance 的 write-up 我没读原文;Anthropic 那份九月威胁报告是通过 frank chu 的评论引的,三小时那条、一百八十万 APK 那条,我都没核。这几个数字当线索用可以,当依据用之前自己核一遍。

二,工具名单和版本差异我基本略过了。Adamson 明确说补丁在动、各产品防护不一,任何精确到版本的判断过几个月就过时——这不是我偷懒,是这块地图在你的工具链上每周都在变,写死了反而是害你。

三,CI 里的 agent 我整块没写。CI 环境里 agent 读的仓库是别人提的 PR,凭证范围也不一样,那是另一个信任模型,值得单独画一张图。这篇先欠着。

四,BotSailor 那条"随着 agent 变强,开发者得重新想信任、权限和工作流"的判断我没展开(BotSailor, 评论区)——它太宽了,宽到没法在地图上钉坐标,而钉不下坐标的话我不想写。留着当标题行可以,当结论不行。

地图画到哪、哪儿空着,说到这儿就够清楚了。剩下的看你的工具链。

全景
全景

选一个技术领域万字横扫:多论文多技术系统梳理成一张全景地图,最后落判断。

查看主页 →