一幅生成式抽象插画,背景为深海军蓝色:左侧的浏览器窗口轮廓将一条由浅色字符状图形组成的带状物,穿过一个狭窄的发光接口,送入右侧的终端面板。第二条颜色更深的带状物从下方汇入同一个接口,其字符在终端中出现时与第一条难以分辨。画面中不出现任何文字、人物或组织徽标。OrcaRouter 的标志置于右下角的白色页脚条带中。
AI Safety Incidents

腾讯 BrowserSkill 只检查了扩展 ID 看起来是否真实——任何扩展都能向智能体提供伪造页面

作者

Rowan Sterling

发布日期

最新模型 · 20查看全部模型 →
基准测试:Artificial Analysis · 每日更新
返回全部文章

在2026年9月17日,一位以carfeii身份发帖的 GitHub 用户针对腾讯的开源BrowserSkill项目提交了 issue #273,其主张十分具体:负责将浏览器扩展连接到 AI 代理的本地守护进程并未检查是哪个扩展发起的连接,而只检查该连接看起来是否像扩展。三天后,即9月20日,VulnCheck 将该发现发布为CVE-2026-94111,其中描述该守护进程“接受任何带有 a-p 范围内 32 个字符的 chrome-extension 源”,将其归类为CWE-346(源验证错误),并归功于George Chen。该公告给出的评分为CVSS 4.0 6.9,中危,其中完整性影响评为高,机密性和可用性为低。记录中没有任何内容表明该缺陷曾被利用:存档未记录任何利用行为,并将该条目的置信度评为 A,real_harm 为 false。这是AI 事件存档中的一条记录,其中每条记录都带有各自的来源、严重程度、置信度评级和争议标记。

一种从不校验身份的格式检查

记录的核心代码很少。在 crates/bsk-cli/src/daemon/ws.rs 中,函数 origin_allowed() 接收 WebSocket 握手的 Origin 标头,去掉字符串 chrome-extension://,如果剩下的内容长度恰好为 32 个字符,且每个字符都介于 a 和 p 之间,就返回 true。这就是完整的测试。它在 HTTP 升级回调中运行一次,失败会返回 403,其消息为“Origin not in chrome-extension allow-list”——尽管按发布版本来说,并没有可供加入的列表。

该模式并非任意。Chrome 的 Manifest V3 扩展 ID 是 32 个字符,恰好由那十六个字母组成,因此该检查能正确识别真实扩展来源的形态。缺陷在于,每个扩展都具有这种形态。该检查只问调用方是否看起来像浏览器扩展,从不问它是否是本项目的浏览器扩展,而它本应比对的标识符早已公开:项目的 README 链接了 Chrome Web Store 条目,其 ID 是hhcmgoofomhgciiibhipgmgkgnoenaoi,以及旁边的 Edge Add-ons ID。这两个字符串都没有出现在该门禁中的任何地方。

该守护进程监听一个固定的本地端口,即 52800,该端口在 CLI 中声明为 DEFAULT_WS_PORT,并在本地连接路径中原样使用、没有任何变体。该端口是有文档记录的常量,且用户浏览器配置文件中已在运行的任何东西都能访问它。位置正是该公告的向量以 AV:L 开头的原因——攻击者需要先在这台机器上取得立足点,而 PR:L 则表明一个低权限的立足点就足够了。安装在同一配置文件中的扩展恰恰就是这类立足点。

这个席位价值几何,其中又有多少已经确立

该公告中关于影响的描述措辞宽泛:攻击者若将恶意扩展注册为浏览器客户端,便可“拦截并操纵返回给 AI 智能体的页面内容、DOM 和截图”。这正是 CVE、GitHub 公告记录 GHSA-x6f2-qp26-2xrh 以及存档中所载的描述,也解释了 CVSS 完整性评级为高的原因。它同样是由分配该 CVE 的一方撰写的摘要,而非对已证实攻击的报告。

同一周,议题线程本身出现了一份更细致的说明。9月20日,一位以 bb6894 发帖的评论者报告称,其对照 main(提交 fa953dc6,9月18日)重新检查了代码,并追踪了外部客户端在握手后实际能够触达的内容。该评论称,大多数入站工具方法会向 WebSocket 对端返回 UnknownMethod;审计请求的范围仅限于客户端自身的记录;而 window_closed、user_interrupt 和 update_interaction 等跨会话操作会受到防护,避免作用于另一个浏览器所拥有的会话。经过这层过滤后仍然存在的能力范围更窄,而且对智能体而言,可以说比拦截更糟:外部扩展能以攻击者选定的 instance_id 占用一个浏览器槽位,并且如果它是唯一注册的浏览器——无论是冷启动还是守护进程重启——它就会收到智能体的工具请求,并用伪造的页面内容、DOM 或截图予以回应。评论者将此称为“针对智能体的结果伪造”和“进入智能体感知的一条通道”。第二个影响是拒绝服务:当也有一个真实浏览器在线且没有选择器时,会话启动可能会因 MultipleBrowsersOnline 而失败。

两种说法都没有在公开场合得到证实。记者将概念验证描述为“可应要求提供”;没有人发表过,也没有记录到任何利用行为。因此,两种说法之间的差异,是同一份源文件的两种解读之间的差异,而不是一种理论与一个可用漏洞利用之间的差异——而且这篇报道把两者都呈现出来,而不是做出选择。可以毫无保留地说的是,握手之后从未进行过第二次身份校验,因此无论网关放行了什么,它在连接的整个生命周期内都保持被放行状态。

代码早就知道了

这份记录中最令人不安的文档并不是那份安全公告,而是紧挨在函数上方的那段注释——它随该公告所指的那个带标签的发布版本一同发布。注释把这一缺口标为 TODO(M10/M12),写明了它打算构建的允许列表——一个DaemonConfig::allowed_extension_ids集合,由配置文件或配对流程填充——随后又说明了为何推迟:“目前算是可接受的纵深防御缺口,因为配对是通过弹窗完成的,但同一台机器上侧载的扩展目前能绕过这道关卡。”

直白地读,维护者知道这道关卡放行的是哪个调用方,记录下了他们知道这一点,然后便发布了。这并没有让暴露程度比公告所说的更大;只是让它不那么令人意外,并把问题从“这是怎么通过审查的”变成“什么会让被推迟的修复变得紧急”。缓解风险的设计假设是真实存在的,并且也有文档记录:本地连接是选择加入的。根据 README,用户安装扩展、打开其弹窗并启用本地连接,而且守护进程必须正在运行,这一切才可能被触达。安装了扩展但关闭了开关,或者没有运行 bsk 守护进程的配置文件,不是监听目标。

五周后,大门依然没有变化。

An HTML timeline card titled 'From a filed issue to an unmerged patch', subtitled 'Nine dated entries in the BrowserSkill daemon origin-check record', listing: 16 September 2026 BrowserSkill extension 0.3.0 tagged; 17 September the bsk CLI 0.3.0 release, and issue #273 filed the same day at 15:14 UTC; 20 September CVE-2026-94111 published by VulnCheck and listed by NVD and GitHub, with a narrower impact analysis posted in the thread; 21 September CISA's SSVC assessment records exploitation none and automatable no; 23 September CLI 0.3.1 released with the same origin check; 28 September pull request #363 opened from a fork to pin the store extension IDs; 30 September CLI 0.3.2, same check; 15 October CLI 0.3.3, same check; 27 October issue still open and the patch still unmerged. A footer cites the GitHub issue, the VulnCheck advisory, NVD and the project's release tags, with the OrcaRouter logo in a white strip at the bottom right.

该记录的影响范围是“至 0.3.0”,而这正是 CNA 指定的范围。但在仓库中,事情并未到此为止。CLI 的 0.3.0 版本于 9 月 17 日 02:22 UTC 打上标签;该问题于同日 15:14 UTC 提交,大约十三小时之后。此后又发布了三个 CLI 版本——0.3.1于 9 月 23 日、0.3.2于 9 月 30 日,以及0.3.3于 10 月 15 日——而在这些标签对应的每个版本中,origin_allowed() 函数仍是上文所述的同一项检查,其上方仍然保留着 TODO。截至 10 月 27 日,主分支也仍然如此。

存在一个修复方案,但仅作为提案。在9月28日,一位以dangzitou身份发帖的贡献者从个人分叉仓库打开了拉取请求 #363,标题为“fix(daemon):将 WS 来源门禁固定到 BrowserSkill 自身的扩展 ID”。它用与两个商店 ID 的比较取代了形状测试,并添加了BSK_ALLOWED_EXTENSION_IDS,作为侧载和开发构建的显式准入路径,这些构建的解包 ID 派生自安装路径。该拉取请求正文声称它同时封堵了伪造路径和 MultipleBrowsersOnline 拒绝服务漏洞。截至 10 月 27 日,它仍处于打开且未合并状态,该问题也仍然打开,且没有任何厂商声明与之关联。

实际后果是,没有任何包含该修复的版本可供升级。任何建议“升级到 0.3.0 之后”的人,都是在建议一个尚不存在的步骤:后续版本只是发布得更晚,并没有修复问题。该记录中的范围应被理解为 CNA 在 9 月 20 日评估的范围,而不是表示 0.3.1 及之后的版本没有问题。

什么是已确立的,什么不是

• 已确认:标签 cli-v0.3.0 处的已发布源码包含一处源校验(origin gate),它会接受任何由 a–p 字符组成的 32 字符 chrome-extension 源。报告者、CNA 以及该文件本身说法一致,且代码是公开的。

• 已确定: 门控仅在 WebSocket 升级时运行一次,之后不再进行身份检查,位于固定的本地端口 52800。

• 已确认:项目自身的源码注释承认,侧载扩展将会通过,并将允许列表推迟处理。

• 已确定: CVSS 4.0 6.9 和 CVSS 3.1 6.6 均为 VulnCheck 的评分,由 NVD 记录为次要评分。NVD 自身对该条目的状态为“已推迟”,这意味着它已发布 CNA 的数据,但未添加由 NVD 编写的分析。

• 已确定:CISA 的 SSVC 评估日期为 9 月 21 日,其中记录利用情况为无、可自动化性为否、技术影响为部分。截至 10 月 26 日,FIRST 的 EPSS 将未来三十天内遭利用的概率定为 0.00135,即第 2.9 百分位。

• 尚未证实:任何真实世界中的使用。没有利用行为,没有已发布的概念验证,没有受影响安装数量。该项目的仓库指标并非安装数量,且无人发布过此类数量。

• 尚未确定:哪一种影响认定成立。CNA 所说的“拦截并操纵”与该讨论帖所说的“结果伪造加拒绝服务”描述的是不同的影响上限,而两者都未在代码阅读之外得到证实。

• 尚未确定:该缺陷止于 0.3.0。版本字符串是 CNA 的评估;其后的三个发布版本中代码未变,且没有厂商声明能排除它们。

• 存在矛盾,尚未解决:有一个聚合器 DevGuard 针对此 CVE 显示“已检测到利用尝试”的信号,但未指明来源、IOC 或遥测数据提供方。这与 CISA 记录的“未遭利用”评估相悖,也与没有任何公开报告的情况相悖;该档案同样未记录任何利用情况。应将该聚合器的标记视为未经证实,而非第二个数据点。

An HTML card titled 'Established, and not', split into two columns. The left column, headed 'Established', lists: an origin gate that accepts any 32-character a-p chrome-extension origin, in the released cli-v0.3.0 source; checked once at the WebSocket upgrade on local port 52800; the project's own comment conceded sideloaded extensions pass; CVSS 4.0 6.9 and 3.1 6.6 are VulnCheck's scores, NVD status Deferred; CISA SSVC records exploitation none and automatable no; EPSS 0.00135 as of 26 October. The right column, headed 'Not established', lists: any real-world use or published proof of concept; which impact account holds, interception or result forgery; that the flaw stops at 0.3.0, since 0.3.1 to 0.3.3 carry the same check; an installation count; an unsourced aggregator claim of exploitation attempts. A footer cites VulnCheck, NVD, CISA, FIRST and the GitHub issue, with the OrcaRouter logo in a white strip at the bottom right.

为什么传输才是有趣的目标

大多数提示注入指南都划出同一条边界:把检索到的页面文本视为不可信,而把传递它的机制视为可信。一个读取网页的工具被认为是在读取该页面;问题在于页面说了什么。这份记录颠覆了这一点。智能体作为页面内容、DOM 和屏幕截图收到的,是本地套接字另一端的客户端选择发送的任何内容,而该套接字上唯一的关卡所问的问题,每个候选者都能正确回答。如果客户端是外来的,“核实页面说了什么”就没有可供核实的依据了。

这也是为什么它的严重级别最终定在这一档,而不是更高。该攻击是本地攻击,它假定配置文件中已安装某个扩展或其他本地代码,并且要求守护进程正在运行且启用了本地连接。这些条件对该工具的目标用户来说很平常,对其他所有人则不寻常。档案中的中等严重级别及其记录的无害结果与这种形态一致:在设计本应管控的那条确切边界上,信任确实被扩大了,但没有证据表明有人越过了这条边界。

下面这条有限的实际建议并非任何人已发布的缓解措施,而只是代码保留下来的边界。由于准入是在已发布端口上的握手阶段一次性决定的,可达面取决于运行守护进程的配置文件中安装了哪些扩展,以及当时该守护进程和扩展的本地连接是否开启。在扩展 ID 允许列表推出之前,这两点就是控制的全部。

A generated abstract illustration on a dark navy field: two identical hexagonal tokens of the same size and colour approach a narrow blue aperture from opposite sides; both pass through, and beyond it their outputs merge into a single stream of pale glyph shapes entering a terminal panel. A faint dotted outline of a browser window sits above. No text, people or organisation logos appear. The OrcaRouter logo is set in the white footer strip at the bottom right.

CVE-2026-94111 的后续走向只有两种。要么拉取请求被合并,这条记录变成一则简短条目,讲的是一处花了些时间才补上的已知缺口;要么一年后同样的形状检查仍在代码树中,而这条记录被引为其所属类别的早期范例:不是承载恶意指令的页面,而是决定智能体正在读取哪个页面的管道。