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

那个 token 从隔壁的进程漏了出来

研究人员从相邻的一个 Cloudflare Worker 里以每秒 12 比特拉出了一枚 JWT,没有逃出沙箱,也没有用到任何内存安全漏洞。isolate 的边界始终没破。秘密还是越了过去,走的是底下的硬件。如今云平台正把同一道边界拿来运行 AI 智能体写出的代码。Bromure Agentic Coding 把线画得更低一层,并且干脆不把你的凭据放进那个盒子里。

某个租户的 JavaScript 向 CPU 提了几百万个形状经过设计的问题,然后从答案里读出了另 一个租户的认证 token。它始终待在平台为它画的边界之内,跑的是普通的 JavaScript,而 那道边界从头到尾都在尽责。

8 月 17 日,一组研究人员发表了 Remote-Timer-as-a-Service,19 日 Cloudflare 也贴出 自己对这项工作的说明。 他们从生产环境中一个同处一地的 Cloudflare Worker 里,以最高每秒 12 比特、99.16% 的准 确率,拉出了一枚 JSON Web Token,也就是服务用来确认你身份的那串签名字符串。针对同一 个平台,此前公开的成果来自 2021 年,速度是每分钟 2 比特。到了 360 倍的速率,你就跨过 了奇闻与被窃凭据之间的那条线。

Cloudflare 已经修好了,三年来没有发现任何人用过的迹象,也表示没有客户数据被访问。往 下读,看看这场攻击自始至终都不必做的事。

没有任何东西非坏不可

Cloudflare Workers 用很少的硬件跑很多租户,做法是省掉平常把他们隔开的那样东西。用 Cloudflare 自己的话说,Workers“在同一个操作系统进程之内,以彼此分离的 V8 isolate 运 行多个租户的代码”。isolate 是 JavaScript 层面的容器:自己的堆、自己的全局、没有共享 内存、没有线程。它在几毫秒内启动,而那正是重点所在,因为进程隔离会让你在每一个请求上 都付出冷启动的代价。

攻击者需要的是跑在某个 isolate 里的代码。把受害者弄进同一个进程才是漂亮的部分:攻击 者的 Worker 去调用受害者。就像研究人员写的,从攻击者的脚本用 fetch("https://victim.example") 调用受害者,“多数情况下会让调度器在完全相同的进程 里拉起一个受害者 worker 的实例”。你不必等待同处一地,你把它召唤出来。

从这里开始就是 Spectre 了。误导分支预测器,让 CPU 推测执行一次它本来绝不该做的读取, 再测量缓存,看它读到了什么。Cloudflare 早已花了数年把这件事变难:没有 SharedArrayBuffer、没有线程、计时器被冻结并粗化,让你测不到小到像一次缓存命中那样的 东西,还有 Dynamic Process Isolation(DyPrIs),它盯着硬件性能计数器,把任何闻起来像 Spectre 的东西挪进独立进程。

研究人员把这些一个个绕了过去。

时钟来自外面。连到 Durable Object,或连到互联网上一台普通时间戳服务器的 WebSocket, 就能在一个拒绝给你时钟的平台里拿到亚毫秒级的分辨率。接着他们没有去提高分辨率,而是把 信号放大:L1 缓存的 tree-PLRU 替换策略沿着二叉树指针走,所以一次缓存事件可以被变成一 长串命中,或一长串未命中。他们写道:“单一缓存事件的时序可以被任意放大。”只要你把要计 时的东西弄得够大,模糊的时钟就够用了。

DyPrIs 漏掉了两次。它是在调用“结束之后”才隔离脚本,而靠 keep-alive 消息维持存活的 Durable Object 可以跑上好几个小时、最长到一整天,于是这个 exploit 在一次永不结束的调 用之内就完成了。它还会用 iTLB 访问次数把分支预测失败归一化,而用 Cloudflare 的话说, “我们的远程计时器就是一个大型 I/O 循环,那些 WebSocket 流量会把 iTLB 活动撑大”。研究 人员把自己的分母养大,直到警报显示一切正常。

剩下的都是管道活儿:一个推测型类型混淆 gadget 用来泄露 isolate 的根地址,对 typed array 的 backing store 做 64 位指针混淆,把它变成任意读取,然后是受害者的 JWT,一次一 个比特。

一个 OS 进程。两个租户。一道用 JavaScript 做成的边界。操作系统进程攻击者 isolatefetch("https://victim.example")把受害者召进这个进程普通的 JavaScript,没有原生代码受害者 isolate自己的堆、自己的全局没有共享内存、没有线程JWT 就在它的地址空间里来自外面的时钟连到时间戳服务器的 WebSocket亚毫秒级的分辨率平台自己的计时器仍旧冻结共用 CPU:分支预测器、L1 缓存、tree-PLRU 替换isolate 的边界在这一层并不存在 — 一次缓存事件被放大成长到连模糊时钟也读得到的一串结果:受害者的 JWT,一次一个比特 — 最高 12 bit/s、准确率 99.16%,2021 年的 360×
攻击者始终没有离开自己的 isolate。它调用受害者,好让调度器把对方放进同一个进程;向平台之外的一个 WebSocket 借来时钟;把单一缓存事件放大成可测量的一长串;再通过两个 isolate 共用的硬件,一比特一比特读出邻居的 token。

补丁比发现说得更多

Cloudflare 推出了三项缓解措施。请把它们合起来读。

他们集成了 V8 Sandbox,把原始的 64 位指针从 JavaScript 堆区域里移走,杀掉了 typed array 那个 gadget。他们教会 DyPrIs 把长寿的 Durable Object 与 I/O 密集的工作负载 当成一等的安全案例,而不是噪声。他们还部署了 Memory Protection Keys,在共用进程之 内,把每个租户的堆放到一道由硬件强制的访问边界后面。

三项全都往 JavaScript 底下伸手,去找比 JavaScript 语义更硬的东西,而第三项直接落在 CPU 本身。Cloudflare 坦率地表示 V8 Sandbox“并不是完整的 Spectre 缓解措施”。用加上一 道硬件层面边界的方式来修补语言层面边界的工程师,已经告诉你他们认为真正的线在哪里。

一个谈智能体编码的博客,写起了 CDN

isolate 已经离开 CDN 了。3 月,Cloudflare 以 Sandboxing AI agents, 100x faster 为题推出 Dynamic Workers,一种在运行时用一秒前还不存在的代码启动 Worker 的做法。如果 你跑过会自己写、自己执行脚本的智能体,你懂那个动机:“如果一个智能体(或一个 MCP 服务 器)要执行 AI 即时生成的代码来完成任务,那些代码总得跑在某个地方”,而且“你不能直接在 自己的应用里对 AI 生成的代码下 eval()”。

Cloudflare 在同一篇文章里点名了那个机制:“Dynamic Workers 使用的,正是整个 Cloudflare Workers 平台自八年前推出以来一直赖以建立的底层沙箱机制:isolate。”理由是速度。一个 isolate 用几 MB 内存在几毫秒内启动,大约比容器快 100 倍、内存效率高 10 到 100 倍,于 是“每个请求一个全新沙箱”变得负担得起,而不必去用一个你反复重用、每一轮都更弱一点的温 池。

Cloudflare 对代价说得很坦率。他们自己的 beta 文章用八个词讲完:“V8 的安全漏洞比 hypervisor 的漏洞更常见。” 那是在有人漏出 token 的好几个月之前写下的。

所以这里的故事是一桩交易,由做这笔交易的人自己写下来,如今又被研究人员标上了每秒 12 比特的价格。问题落到了其他所有人身上。当被放进沙箱的代码是模型写的,被某个包或某个网 页讲的话塑形过,然后被留在一枚 bearer token 旁边跑着,那是你想要的交易吗?

Bromure 把线画在 hypervisor

Bromure Agentic Coding 不会把你的智能体放进一个语言层面的容器,跟别人的代码挤在一起。 每个工作区都是一台跑在 Apple Virtualization.framework 上的 Linux 虚拟机,只支持 Apple Silicon:自己的内核、自己的客户机内存、自己从只读基础镜像克隆出来的磁盘。没有共用进 程,就没有可以召唤的同居租户;你的智能体所在的那道边界是 hypervisor,也就是 Cloudflare 自己那个比较里漏洞更少的那一边。

那是架构层面。真正会让这场攻击变得毫无意义的东西更窄,而且还要再往里走一步。

token 从来就不在盒子里

研究人员带走的,是一枚躺在受害者地址空间里的 JWT,也就是一个运行中的服务放置自己所用 凭据的地方。他们没有拿到 shell,也没有拿到 root。

Bromure 的工作区不会把凭据放在那里。

一个配置文件里的每一个秘密都留在你的 Mac 上。这涵盖 ANTHROPIC_API_KEY、GitHub 个人 访问令牌、AWS 访问密钥、kubeconfig 的 bearer token、容器镜像仓库的 Basic-auth blob,以 及 Linear 密钥。Bromure 注入虚拟机的是假的:一个 brm_… 占位串、一张用完即弃的客户端 证书、一段派生出来的 Basic 字符串。智能体读它,SDK 读它,gitkubectldoctl 也读它,工作照样跑得通,因为主机上的 MITM 代理会在出站请求上换回真正的值。AWS 那边还 多拧了一圈:主机会用真正的材料重新签署 SigV4 请求,所以任何绕过代理的东西从 Amazon 拿 回来的是 InvalidSignatureException,而不是一次成功的调用。

于是,一个在那台虚拟机里握有完美任意读取能力的攻击者,也就是研究人员花一整篇论文才搭 出来的那个 primitive,读到的是诱饵。字节确实在那里,能被解析,看起来像一把密钥,却在 机器外买不到任何东西。不论隔离边界是否完美无瑕,你都能得到这个结果,因为工作区里根本 没有值得偷的东西。

传统做法:边界是软件,而秘密就在里面isolate 里的智能体代码和其他租户共用一个 OS 进程真 token 就在它的地址空间里底下的共用硬件缓存与分支预测器把边界挡下的比特带了过去邻居读走 token12 bit/s、99.16%BROMURE:边界是 hypervisor,而秘密在它的另一侧工作区虚拟机自己的内核与内存,没有同居租户ANTHROPIC_API_KEY=brm_…假的 — 任意读取读到的是诱饵MITM 代理,主机端把假的换成真正的值egress 规则决定字节能去哪里每次使用可选择弹出同意对话框真正的 API看到的是真凭据而且是从你的Mac 发出去的每一次替换、每一条被允许与被拒绝的连接:Window → Security Timeline 里的一行,写在虚拟机之外
传统上,邻居与你的凭据之间就只隔着沙箱边界,而凭据就放在沙箱里面。在 Bromure 的工作区里,边界是 hypervisor,凭据放在它的另一侧:客户机握着一份假的,而客户机够不到的那个代理会在链路上换成真正的值。

每秒十二比特,还是得有地方可去

侧信道只是外泄的一半。另一半是一条往外的路,而每秒 12 比特意味着这条路得开着一阵子。 一枚 400 字符的 token,意味着要往攻击者控制的目的地送上好几分钟的流量。

一个 Bromure 配置文件带着自己的 egress 规则,写成一小段 pf 风格的策略,并以表格的形式 编辑。强制执行的是你的 Mac,发生在虚拟交换机与代理里,客户机内部的任何东西都没有发言 权:被拒绝的连接会收到 reset,而这个决定会带着主机、IP、端口与判定,变成 Window → Security Timeline 里的一行 egress.firewall。跑在工作区里的代码,站在它 想改的那些规则的错误的那一侧。

你也可以在每一次动用真凭据时按住它。对每个秘密打开 Require approval to use:模型的 API 密钥、SSH 签名、GitHub 与 GitLab 与 Bitbucket 的令牌、每个 kubeconfig 上下文、 DigitalOcean、每一次 AWS SigV4 签名、每个容器镜像仓库,以及你自己加上的任何手动令牌规 则。替换会就地停下,等一个 macOS 上的对话框,你可以授权五分钟、一小时,或整个会话。客 户机永远没有机会回答那个问题。

交易本身才是故事

isolate 是很好的工程,而 Cloudflare 的处理方式正是你会希望看到的:协同披露、三项实在 的缓解措施、对 V8 Sandbox 覆盖什么与不覆盖什么绝不打太极。每秒数百万个请求不跑在容器 上,是有原因的。

冷启动是在 CDN 上赢下这场争论的东西,但你的编码智能体并不是在四毫秒内回答一个 HTTP 请 求。它会跑一个小时,装上没有人审计过的包,执行模型写的测试套件,读那些很想跟它说上几 句话的网页。不论是什么在跑这个工作负载,它在整段期间都握着你的令牌,而关于它所执行的 代码,你唯一知道的事情就是那不是你写的。

对这样的工作来说,几百毫秒的虚拟机开机时间不是值得省下的成本。Cloudflare 已经公布了汇 率:V8 的漏洞比 hypervisor 的漏洞更常见。Bromure 站到这笔交易的另一边,然后顺手把令牌 也带出了房间。


资料来源:Schwarzl, Xiao, Pedersen, Ainsworth, Topham,“Remote-Timer-as-a-Service: Efficient Microarchitectural Leakage in the Cloud with Remote Timers”(arXiv:2608.17043,2026 年 8 月 17 日) · Cloudflare,“A revisit of remote Spectre attacks on Cloudflare Workers”(2026 年 8 月 19 日) · Cloudflare,“Sandboxing AI agents, 100x faster”(2026 年 3 月 24 日) · The Hacker News,“Cloudflare Workers Spectre Attack Leaks JWT From Co-Located Worker at 12 Bits/Second”(2026 年 8 月 19 日)