漏洞

Chromium CVE-2026-15123 中 Document.append() 恢复执行时的过期树状态

CVE-2026-15123 的永久修复提交 cb26b6a1eb79 把 Blink 实时结构复核移到 Document 分支之前;资产应安装厂商当前稳定版并清空旧 renderer,下游须证明等价源码与完整 WPT 均已进入产品,LTS-144 截至 2026 年 7 月 26 日仍缺少公开的已合并回移。

暖色手绘画面展示 DOM 分支、待处理节点卡片、带生命周期回调的 iframe 场景、节点转移过程与最终结构检查位置。
文章导航

研究依据本次复核覆盖 2026 年 7 月 8 日 Chrome 公告、父提交 53096e81cb32、修复提交 cb26b6a1eb79、Blink Node 与 ContainerNode 精确调用路径、完整 WPT 与 .headers 伴随文件、M148/M149/M150 回移和截至 2026 年 7 月 26 日的产品状态。

来源Chrome 安全公告 / Chromium 固定提交源码与 Gerrit 回移记录 / WPT 固定提交回归 / NVD

1 先完成升级、进程替换和回归验证

这项漏洞需要永久修复。Google 在 2026 年 7 月 8 日把 CVE-2026-15123 列为 DOM 高危漏洞,并发布 Windows、macOS 的 150.0.7871.114/.115 与 Linux 的 150.0.7871.114。NVD 收录的 CNA 描述使用“早于 150.0.7871.115”这一统一边界;平台公告说明 Linux 的安全构建是 .114,所以版本判断必须同时带上平台和厂商通道。到 7 月 21 日,常规桌面稳定版已经推进到 Windows、macOS 150.0.7871.181/.182 和 Linux 150.0.7871.181。今天的默认动作是安装资产所属厂商当前提供的稳定版,7 月 8 日的号码只用来判定历史暴露窗口。

1.1 修复对象、验收条件和失败处理必须写进同一张变更单

代码对象。 漏洞路径位于 Blink 的 third_party/blink/renderer/core/dom/container_node.cc。在父提交 53096e81cb3220c0a1ebf0a4b0115a1a4207ca10 中,EnsurePreInsertionValidity()Document 分支从第 277 行开始,return 表达式跨第 283—284 行,共享结构复核位于第 335—340 行。修复提交 cb26b6a1eb7999001e771a07944d4cb0e377341c第 277—283 行解释为何需要复核,于第 284—288 行执行条件判断与复核调用,随后才在第 291—298 行进入 Document 专用检查。所有等价回移都应保留这条控制流支配关系。

受影响状态。 Chrome 桌面资产低于厂商对应平台的 7 月 8 日安全构建时需要升级;Edge、Brave、Electron、CEF、WebView 和其他 Chromium 下游不能借用 Chrome 的版本号完成关单,它们需要供应商公告、源提交映射或二进制来源证明。自研 Blink 分支还要核对合入点:M148、M149、M150 的公开回移已经合并,LTS-144 的 Gerrit 回移截至 7 月 26 日仍为 NEW,因此 LTS-144 不能仅凭“长期支持”标签视为已经覆盖。

永久动作。 从受信任更新通道安装当前稳定包,校验包签名与来源,重启浏览器、宿主应用或设备,确认所有加载旧 Blink 的 renderer、utility 与预加载进程已经退出。自研分支应合入固定提交或保持相同顺序的等价补丁,并重新生成可追溯的构建。仅修改版本字符串、关闭断言或在崩溃点增加容错都无法恢复被破坏的树结构契约。

临时限制。 暂时无法升级的资产应退出不受信任网页、邮件 HTML、广告内容与外部嵌入页面的处理范围;嵌入式产品可以将浏览能力隔离到无敏感会话、无本地特权的独立环境,并限制可达站点。禁用 JavaScript、iframe 或单个生命周期事件会破坏正常业务,而且其他同步回入入口仍可能改写 DOM,这些开关只能降低暴露面。高价值授权、管理后台和本地文件桥接场景需要优先停用旧运行时。

验收与撤回。 关单证据至少包含平台、通道、完整版本、包签名或构建提交、更新时间、活动进程版本,以及完整回归文件和伴随 .headers 的结果。诊断构建应在父提交上稳定触达 !target_node->parentNode() 断言,在修复提交上安全结束;发布构建也要完成同一页面且 renderer 存活。升级引发业务故障时,撤回路径应切换到另一个已经修复并验证的浏览器或应用构建,或者继续隔离该功能。恢复旧包、保留旧进程、只复制 HTML 而遗漏响应头、下游无法说明补丁身份,均属于验收失败。

1.2 六个连续步骤说明 JavaScript 如何改变 C++ 恢复时的前提

这里先固定四个术语。Document 是 DOM 树的文档根节点,顶层子节点受文档元素、doctype 与文本节点规则约束;Element 是普通元素节点,走另一条容器检查路径;WPT 是 Web Platform Tests,用跨实现测试固定 Web 平台行为;DCHECK 是 Chromium 诊断构建用于暴露内部契约破坏的断言,它标出最先可重复观察到的失效位置,产品风险仍以厂商安全公告为准。

步骤执行者与对象保存或改变的状态对后续 C++ 的意义
1页面调用 doc.append(node1, trigger)外层操作保存两个候选节点及其顺序调用方期望二者进入独立的目标 Document
2Node::ConvertNodeUnionsIntoNodes() 准备多节点输入现有节点从旧位置移出;trigger 所含 iframe 随之断开准备过程已经触碰实时 DOM,入口处判断开始过期
3iframe 的 unloadpagehide 回调作者 JavaScript 在原生调用栈尚未退出时同步执行外层局部变量仍在,节点关系却可被脚本合法改写
4回调执行 div.appendChild(node1)node1.parentNode 从空值变成该 div候选身份与顺序未变,“候选无父节点”的前提已经失效
5外层 EnsurePreInsertionValidity() 恢复旧版 Document 分支在共享复核前返回文档构成检查通过后,已有父节点的候选仍被交给插入层
6InsertNodeVector() 消费候选旧版在父节点为空的契约处触发断言;修复版先读取当前树并安全拒绝补丁在最后一次脚本回调之后重新建立可用前提

这条序列是同步回入,时间顺序完全确定。没有第二个线程同时争用节点,也不需要页面构造伪造的 C++ 对象。外层调用保持存活,内层回调改变同一批真实 DOM 对象,随后 C++ 从原位置继续执行。审计时应寻找“调用脚本前验证、脚本返回后继续消费”的边界,并把复核位置放在最后一个可执行作者代码的步骤之后。

手绘图左侧是保持两个候选身份和顺序的容器,右侧是其中一个节点已连接到另一棵 DOM 树的实时结构,中央量具表示恢复执行前需要比较两种状态。
图 1。候选集合仍准确记录对象与顺序,实时 DOM 已增加一条父子关系;恢复执行时必须重新读取后者。

2 精确源码路径把过期前提连到最终断言

2.1 Node::append() 的多参数准备会执行可观察的节点移除

固定到修复提交后,JavaScript API 与底层插入之间的关系可以逐段核对。node.cc 第 1020—1038 行实现 Node::append():第 1031—1033 行把节点与字符串交给 ConvertNodeUnionsIntoNodes(),第 1037 行调用 AppendChildren()。转换函数位于第 915—996 行;第 925—943 行构造 nodes,第 945—968 行是关于多节点使用 DocumentFragment 模拟的设计注释,可执行的多节点移除与去重分支位于第 969—994 行,其中第 977 行执行 node->remove()。这一步能够触发 iframe 脱离及生命周期回调,所以它是本案中旧判断失去时效性的明确边界。

控制回到 ContainerNode 后,AppendChildren() 第 1164—1196 行先在第 1166—1169 行调用 EnsurePreInsertionValidity(),再于第 1192—1193 行把候选交给 InsertNodeVector()。低层函数位于第 388—415 行,第 395—396 行进入禁止事件与脚本执行的作用域,第 399 行断言目标节点当前没有父节点,第 401 行调用实际变更器。第 402 行随后建立 ChildListMutationScope,用于记录这次子节点列表变更。断言前已经禁止新的脚本执行,因此失效状态来自更早的准备回调。

父提交把共享复核放在普通容器路径中。第 244—341 行展示完整旧结构:函数从第 244 行开始,Document 分支在第 277 行进入,return 表达式跨第 283—284 行;普通多节点路径在第 321 行进入 new_children 块,并在第 335—340 行调用共享复核。外层目标是 Document 时,当前树中的 node1.parentNode 没有被这次复核读取。

共享函数本身已经覆盖了所需条件。父提交的第 361—385 行先在第 365—370 行检查候选是否仍有父节点,再在第 371—379 行重做 Document 接纳检查,第 380—383 行检查祖先关系,第 385 行核对引用子节点。修复提交中同一帮助函数位于第 360—384 行。漏洞根因是调用位置;现有帮助函数已经提供所需验证。

复核发现候选已有父节点时,第 365—368 行直接返回 false;文档构成、祖先链等其他分支会在需要时使用 Blink 的异常状态,AppendChildren() 随后不会调用 InsertNodeVector() 消费这批候选。上游 crashtest 用 try/catch 容纳标准 DOM 检查可能产生的异常,同时把核心验收项保持为“过期候选没有进入低层变更器”。测试若强行要求一种异常文本或固定消息,会把与安全性质无关的实现细节写进回归。

候选身份与候选结构在这里必须分开理解。转换过程仍然持有预定节点对象的有效引用,也保留调用方给出的顺序;垃圾回收与生命周期机制可以让这些对象在回调期间继续存活。插入契约仍会过期,因为其中一个活着的对象获得了父节点。内存存活、对象身份、参数顺序、目标文档构成和树所有权是五项不同性质,旧路径保存了前三项,却没有在消费前刷新最后一项。

最终断言因此是有用的因果标记:它写出了低层插入的明确前提,上游回归又展示了标准网页能力如何破坏该前提。发布配置可能没有同样的诊断断言,也可能让不一致状态在更晚位置表现出来。源码复核沿“回调—过期关系—消费者”追踪契约,产品响应沿厂商给出的高危内存安全定级行动;两条证据线分别处理诊断构建和生产构建,结论不会被一条断言的编译状态左右。

2.2 cb26b6a1... 让共享复核支配 Document 与普通容器分支

修复提交由 Chromium Gerrit 评审 7963938 合入主线,提交位置是 refs/heads/main@{#1650442}。修改后的 EnsurePreInsertionValidity() 在第 277—283 行解释为何需要复核,于第 284—288 行执行条件判断并调用 RecheckNodeInsertionStructuralPrereq(),之后第 291—298 行才执行 Document::CanAcceptChild() 并返回。普通 Element 路径和 Document 路径此时共享同一个回调后检查点。

CanAcceptChild() 处理文档顶层结构:文档元素、doctype、文本子节点及顺序是否允许。候选节点当前是否仍然游离属于另一项事实。修复后的顺序先确认候选父节点、祖先链和引用节点与实时树一致,再检查目标 Document 能否接纳这组节点。两项检查分别回答对象状态与目标结构,任何一项失败都会在进入禁止脚本的低层变更区之前结束。

共享帮助函数保护的范围还包括本次断言之外的结构条件。它遍历每个候选,在回调后刷新文档构成,拒绝会形成无效环路的 host-including 祖先关系,最后确认传入的引用子节点仍属于预定容器。回调可以让其中任何关系过期,同时保持对象引用有效。把帮助函数移到分支之前,会为整批候选恢复同一条时序规则;下游若只给 node1.parentNode 增加特判,只能覆盖公开样例,旁边的过期结构路径仍然存在。

补丁的安全作用来自控制流支配:所有相关分支在抵达 InsertNodeVector() 之前都必须穿过共享复核。下游审计不能只搜索函数名或补丁文本;一个分支可以同时包含帮助函数与 CanAcceptChild(),调用顺序仍然保留原漏洞。可靠的回移证明应给出固定提交、源文件范围、目标分支和生成该二进制的构建身份,并明确复核发生在 Document 提前返回之前。

公开回移记录为当前分支提供了可核对的锚点:M148 的评审 8020702 合入提交 45d7457ac585f71bb09b80048b6fea2c321e02be;M150 的评审 8020722 合入 7fec1606c3ae38328980dffc7cb7b4644bfb5e88;M149 的评审 8031406 合入 a6854c7506373b375d734e7433905952814921c8,其 7827_199 分支评审 8036160 合入 b4c32f6dce704bc210e0ddc1be5f39aa420f165b。这些记录证明源分支存在回移,产品包仍需另行绑定到对应构建。

M144-LTS 的评审 8139164 截至复核日处于 NEW,公开页面没有给出已合并提交。ChromeOS 公告同时说明 LTS 通道继续停留在 144,LTC 通道开始转向 150。使用 LTS-144 的组织应向供应商取得此 CVE 的明确覆盖说明;在证明到达前,保持前述不受信任内容限制。评审里的当前 patchset 哈希只能表示待审代码,不能替代已合并、已构建、已部署三项证据。

回移分支周边代码会发生差异,精确行号可能随之小幅移动,因此评审记录要把函数、相邻条件和相对顺序一起保存。M150 的合入版本虽然包含分支自己的其他改动,回调后复核仍位于 Document 分支之前。用这种方式核对 M148、M149 与私有分支,可以发现一种危险的冲突解决:补丁文本大体存在,实际调用顺序却被合并过程恢复成旧路径。

左右对照的手绘处理路径:旧路径在共同检查前分叉并亮起红灯,修复路径让两条分支先经过同一检查点再进入后续插入。
图 2。源码改动移动检查点,使 Document 与普通容器分支都在低层插入前读取回调后的实时树。

3 回归由 41 行 HTML 与一行响应头共同构成

3.1 主文件固定调用链,.headers 保证生命周期入口可用

Chromium 修复提交新增的主文件是 third_party/blink/web_tests/external/wpt/dom/nodes/crashtests/multiple-append-mutated-in-unload-document.https.html。目录中的 crashtests 是路径组成部分,省略这一层会指向不存在的文件。WPT 同步提交 bb2448912693c0a7239a549ad4e84aebcfbc4ebf 保留了同一相对路径,可作为独立仓库中的固定证据。

主文件第 7—23 行定义 makeTrigger():创建 iframe 与承载元素,将它们连接到页面,为 unloadpagehide 注册一次性处理,并保证回调只改变现场一次。第 26—38 行创建独立 Document、脱离树的 div 和注释节点 node1;回调执行 div.appendChild(node1),随后测试在 try/catch 中调用 doc.append(node1, trig)。这份 crashtest 判断进程生存状态,并容纳标准 DOM 检查可能产生的异常,不规定一种可见文本结果。

同目录的伴随文件 multiple-append-mutated-in-unload-document.https.html.headers 只有一行:Permissions-Policy: unload=*。它允许测试使用所需的 unload 生命周期路线。单独复制 HTML、让测试服务器漏发这个响应头,可能导致回调路线没有被执行;页面安静结束只能说明测试条件不完整。完整文件名、目录、响应头和服务器行为都应写进实验记录。

一份足以复核的最小测试收据应记录主文件和 .headers 的 SHA-256、WPT 提交、请求 URL、HTTP 状态、浏览器实际收到的 Permissions-Policy、浏览器或自研构建提交、运行配置、回调计数、退出状态和 renderer 进程结果。它能区分四类表面相同的“没崩溃”:修复确实拦截了过期状态、策略阻止回调、错误路径返回 404、测试运行器根本没有等待页面完成。记录这些字段比堆叠多次无上下文运行更能说明补丁是否真正受到考验。

测试平台展示结果时,应把预期写成“页面完成、renderer 存活、回调已执行”,并把捕获到的 DOM 异常作为诊断字段保存。使用笼统的绿色 PASS 会隐藏生命周期路线是否真正发生;把异常本身标成失败又会误判修复后的安全退出。三项状态分开记录后,自动化结果与人工源码复核才能对应到同一条因果链。

该 WPT 没有 “PASS” 字符串、DOM 断言输出或截图基线。预期结果是页面执行完毕且 renderer 保持存活;一个标准允许的异常可以被 try/catch 消化。诊断构建中的负对照应显示父提交在 container_node.cc 的父节点为空契约处失败,修复提交应在抵达低层断言前根据实时结构结束。发布构建的成功条件同样是进程存活与后续导航正常,不能把诊断断言是否编译进包当作唯一判断。

测试文件名中的 .https 也是执行契约的一部分。WPT 服务器提供安全上下文、响应头与确定的目录资源;直接从磁盘打开保存的 HTML 会改变来源和策略条件。把夹具移植到内部运行器的团队应保存浏览器最终收到的响应头与控制台输出,并逐项写明相对上游服务器的有意差异。本地改写版本可以辅助调试,固定提交中的完整上游包仍是验收基准。

3.2 正负对照分别回答可达性、因果性与回归风险

第一组对照固定源码差异:用相同工具链分别构建父提交 53096e81... 和修复提交 cb26b6a1...,保留 GN 参数、编译器、目标架构、二进制哈希与 WPT 服务日志。父提交的诊断构建负责证明公开页面能把已有父节点的候选送到低层契约;修复提交负责证明移动后的检查点阻断同一因果链。两个结果共同说明补丁位置与运行时变化相互对应。

第二组对照固定触发因素。保留 iframe 与响应头,但让回调不移动 node1,可以验证生命周期回调本身不会造成该断言;保留回调中的重新挂载,但只传入单个节点,可以区分多节点转换路径;把目标换成普通 Element,可以确认旧版共享复核原本覆盖的路线;保持 Document 目标则覆盖漏洞分支。这些变体适合放入实验附录,正文只保留它们改变结论的部分。

还有一项很有价值的变体:回调先移动 node1,再在外层 append 恢复前把它还原成无父节点状态。修复后的帮助函数应读取最终实时关系,让后续检查决定操作结果;它不应因为回调历史上改过树就一律拒绝。另一变体在回入期间移动或删除引用子节点,验证帮助函数最后的锚点检查能够捕获过期关系。两项变体表明,修复以回调结束时的完整契约为判定依据;生命周期回调本身仍然合法,判断也独立于一段固定历史序列。

第三组对照检验正常语义。普通多节点 append 要保持参数顺序,字符串仍转换成文本节点,合法的 Document 组成仍能成功,非法的 doctype、文档元素或文本组合仍通过标准异常结束。安全补丁的验收范围包含“阻断过期状态”和“保留正常 DOM 行为”。只观察 crashtest 没有崩溃,可能漏掉一个把所有 Document.append() 都拒绝掉的粗糙回移。

稳定执行还需要确认回调真正发生。测试日志或临时诊断计数应记录生命周期处理器被调用一次、node1.parentNode 在回调后指向 div、外层调用随后恢复。运行若因策略、无头环境或测试服务器配置跳过 iframe 生命周期,结果应标为未覆盖。重复多次可以发现测试夹具的不稳定性,重复次数不代表真实攻击成本,也不能转换成利用概率。

构建配置提供另一组必要对照。诊断配置让被破坏的父节点为空契约直接可见;接近生产的 release 配置用于确认断言和插桩变化后,回移仍然兼容且进程存活;sanitizer 构建可以在不一致状态越过最初标记时观察更晚的内存后果。每项结果都要标出自身配置,不能把一种配置的结果换名成另一种配置的证明。

这份回归是良性的公开验证材料:它建立状态错位和进程失败之间的因果联系,没有提供沙箱逃逸、稳定内存破坏原语或端到端利用。安全团队可在隔离实验环境中运行上游文件。生产巡检的证据来自版本、包与进程;向终端用户会话注入该测试会增加风险,也不会提供部署证明。公开复现边界足以验证补丁,进一步开发利用链不属于部署关单的必要条件。

4 网页可达、高危内存影响与分支状态各有独立证据

4.1 源码、回归和产品公告回答三个不同问题

固定源码回答机制问题:节点准备能够同步执行作者脚本,脚本给候选设置新父节点,旧 Document 分支跳过共享复核,低层插入仍要求候选无父节点。WPT 回答网页可达性问题:标准 DOM、iframe 生命周期和普通 JavaScript 足以走完这条顺序。Chrome 公告与 CVE 记录回答产品影响问题:厂商将其归为 DOM 中的不当实现、高危,并描述精心构造的 HTML 可能造成堆损坏。三层证据连接后,升级优先级不依赖对一条调试断言的猜测。

公开材料没有给出稳定的代码执行链、Chrome 沙箱逃逸或在野利用事件。NVD 的 CISA ADP 数据在复核时给出 8.8 分并把利用状态标为无公开活动证据。这个边界只约束已知事实:安全响应仍按网页可达的高危内存安全漏洞处理,同时不会把断言复现写成已经实现任意代码执行。若后续厂商更新利用状态,威胁狩猎与隔离优先级需要随之调整。

同一机制可以出现在网页浏览器、桌面应用内嵌 Chromium、富文本预览、帮助中心、邮件阅读器、广告容器、自动化截图服务和服务端 HTML 渲染中。判断对象是实际加载 Blink 的运行时。系统默认浏览器已经更新,不会自动更新 Electron 应用随包携带的 Chromium;主程序版本很新,也不能说明它的 CEF 或 WebView 依赖包含修复。资产清单应采集产品、平台、通道、Chromium/Blink 基线、进程路径和供应商补丁说明。

网络设备难以从普通 DOM 使用中识别这项漏洞。触发页面可以动态创建节点和 iframe,脚本可以被打包、内联或来自受信任站点中的第三方内容,TLS 又隐藏响应体。把某段测试代码转成 IDS 签名只能命中特定样本。可靠监测面位于资产与运行时:落后版本、更新失败、旧进程长期存活、异常回退、供应商覆盖未知,以及 renderer 崩溃或站点隔离进程异常重启。

崩溃调查应先保存完整版本与命令行、模块哈希、进程类型、符号化栈、页面来源和前后导航,再看 ContainerNode::EnsurePreInsertionValidityRecheckNodeInsertionStructuralPrereqInsertNodeVector 以及节点移除、frame detach、adoption 附近帧。发布构建中的堆损坏可能晚于最初错误状态显现,最终栈不一定保留 append 函数。函数名提高关联度,版本与页面时序负责确定范围。

严重性与利用状态是两项独立的运维字段。高危定级推动修补优先级,因为不受信任 HTML 可以抵达原生内存安全条件;公开利用状态影响紧急狩猎、隔离范围和事件假设。没有可疑崩溃的资产仍要升级,出现可疑崩溃的资产也要经过版本与因果核验才能归因。两项决策分别记录,可以防止一个不确定字段削弱已经得到充分支持的行动。

4.2 产品版本用于部署,提交身份用于证明下游等价性

Chrome 桌面的历史最低安全构建以 7 月 8 日官方公告为准:Windows 与 macOS 接收 150.0.7871.114/.115,Linux 接收 150.0.7871.114。CNA 使用统一的 150.0.7871.115 上界描述受影响版本,这适合做保守筛查;Linux .114 是否安全应回到平台公告。部署当天若厂商已发布更高稳定版,更新到当前稳定版可以同时获得后续安全修复,并避免把一个旧的最低值固化成长期目标。

ChromeOS 需要区分 Stable、LTC 与 LTS。7 月 16 日的 Stable 公告给出浏览器版本 150.0.7871.150;7 月 21 日长期支持公告说明 LTC 正转向同一 150 基线,而 LTS 保持 144 到 10 月 6 日。公开 M144 回移仍未合并,使 LTS-144 的覆盖成为明确待办。组织可以获得厂商私有补丁证明、转到含修复的通道,或者继续隔离不受信任内容;通道名称本身不提供此 CVE 的逐项证据。

Chromium 下游常重新编号、延迟合并或维护私有补丁。合格证明可以是包含 cb26b6a1... 的提交图、列明等价修改的供应商公告、固定分支中第 284—288 行相同支配关系,或者供应商提供并可追溯到构建的安全清单。最终证明是活动 renderer 中对象代码的来源;大于 150 的营销版本、仅在上游主仓库出现的补丁和 SDK 包里的新头文件只能作为调查线索。

WebView 的更新责任需要按产品回答。有的平台由系统 WebView 或 Chrome 组件独立更新,有的平台把引擎编译或打包进应用自身,企业策略还可能固定其中任一层。资产记录应包含提供者包名、活动进程报告的引擎版本、更新责任方和重启行为。宿主应用升级而被固定的系统组件仍旧,或者系统组件升级而应用继续加载私有 CEF 构建,都会留下内容入口。通过对象是实际加载模块;管理控制台只记录更新发起动作。

同一升级队列中的优先级可以由内容可信度与 renderer 权限决定。能够浏览任意互联网内容并持有登录会话的桌面浏览器排在前面;带本地文件、剪贴板、密钥或原生消息桥的嵌入式 renderer 也应进入最高队列,因为浏览器进程之外的宿主能力会扩大一次 renderer 失陷后的后果。只渲染固定、签名、本地模板且运行在无凭据隔离环境中的 worker 可以稍后处理,但仍须永久更新。这个排序用于安排窗口,不改变任何受影响运行时的最终退出条件。

回移后的源行号可能因分支差异发生少量移动,所以核验同时保存函数、相邻条件和顺序。M150 合入提交中的复核同样位于 Document 分支之前;M148、M149 记录提供各自的 Gerrit 审批与提交身份。源证据完成后,仍要从构建产物或 SBOM 连到部署包,再从包连到活动进程。任何一段缺失都应保留为未知,不应由相邻产品的状态代填。

更新窗口应覆盖持续运行的浏览器会话、休眠终端、VDI 模板、容器镜像、自动化 worker、安装包缓存和灾备镜像。Chrome 的 UI 版本页可以证明新包已经安装,进程级模块信息可以证明旧 renderer 已退出,镜像清单可以防止下一次扩容重新投放旧版本。变更单还应给出所有者和完成时间,避免一次成功抽样被误写成全网完成。

回滚库存要接受与活动资产相同的核验。终端管理工具可能保留上一版安装包,企业软件分发系统可能继续缓存已替代构建,虚拟桌面也可能在健康检查失败后恢复旧快照。应明确第一项安全回滚候选,并撤销漏洞构建参与自动回退的资格。这样,故障恢复过程无需在停机压力下重新判断安全边界。

5 终端资产与 Blink 集成方使用两套验收清单

5.1 终端资产关心厂商包、活动进程与暴露面

普通企业资产没有必要自行编译 Chromium;它们的主要任务是把供应商修复送到所有实际处理内容的运行时。下表把对象、动作、证据、通过条件和失败条件放在一行,便于直接转成部署工单。每个资产实例都要保留自己的结果,抽样只用于发现流程问题。

对象动作证据通过条件失败与处置
Chrome 桌面从受信通道安装当前稳定版并重启平台、通道、完整版本、包签名、更新时间达到厂商当前版本,旧 renderer 全部退出更新失败或旧进程仍在:隔离内容处理并重试部署
ChromeOS Stable/LTC/LTS核对通道基线与 CVE 覆盖;LTS-144 请求厂商证明设备通道、OS/浏览器版本、供应商逐项说明运行含修复的 150 基线或取得可追溯等价补丁覆盖未知:限制不受信任页面并评估换通道
Edge、Brave 等下游浏览器安装各自厂商当前安全版厂商公告、产品版本、Chromium 基线或修复映射供应商确认 CVE-2026-15123 已覆盖且活动进程已替换只见 Chrome 版本对应关系:保持未验证状态并向供应商升级
Electron、CEF、WebView 与嵌入式应用更新应用包或运行时,重新发布宿主应用版本、内嵌 Chromium 提交、包哈希、进程模块宿主实际加载的 Blink 对象含等价修复宿主无法更新:关闭外部内容入口或迁移到已修复渲染器
镜像、VDI、自动化与灾备更新模板、缓存和伸缩源并重新实例化镜像摘要、生成时间、新实例版本抽查新旧实例都不再出现漏洞基线旧模板可再次投放:停止扩容并撤销旧镜像资格

运行时盘点要按内容入口扩展。用户可点击的浏览器、后台网页截图进程、富文本预览、OAuth 登录窗、插件市场、内置帮助页和广告 SDK 都可能加载 Blink。资产没有外网出口时,仍需检查本地 HTML、同步内容和供应链输入。风险降低措施应写明覆盖的入口与剩余入口,不能使用“内网应用”作为统一豁免。

终端验收应在维护窗口结束后读取进程状态,安装期间的包管理器结果只覆盖落盘动作。浏览器可以让旧 renderer 活到所有窗口关闭,kiosk 宿主可能监护并重新启动旧子进程,桌面应用也可能在更新代理运行前预加载 WebView。更新后的短时盘点应保存可执行路径、进程启动时间与加载版本;窗口期间离线的设备保持待处理状态,重新上线时继续应用临时限制。

5.2 Blink 集成方关心源码顺序、完整 WPT 与构建可追溯性

维护 Chromium 分支或自研浏览内核的团队需要源级闭环。它们既要证明修复代码存在,也要证明回移没有改变 DOM 正常语义,最终发布物确实来自该源码。下表把这些阶段分开,任何一行失败都应阻止发布候选进入生产。

对象动作证据通过条件失败与处置
源码分支合入固定提交或等价移动共享复核父/修复提交、评审、精确函数与相邻行复核支配 Document 返回与 InsertNodeVector()只有函数或断言改动:退回重新审查控制流
WPT 夹具同步 crashtest HTML 与同名 .headersWPT 提交、文件哈希、服务响应头、回调计数回调执行一次并重新挂载 node1事件未触发或响应头缺失:结果标为未覆盖
诊断构建用相同工具链运行父提交与修复提交GN 参数、编译器、架构、二进制哈希、崩溃日志父版触达父节点断言,修复版安全结束两版结果相同:检查夹具、回移和构建污染
语义回归运行普通 append、Document 结构与 Element 路线测试测试清单、通过记录、异常类型与节点顺序合法操作保留,非法组合按标准失败广泛拒绝或顺序变化:修正回移后重跑
发布产物把源码身份绑定到签名包并做产品冒烟可复现元数据、SBOM、包签名、模块哈希、运行版本发布 renderer 来自已验收源码且 WPT 后仍存活映射断裂:阻止发布;仅可切换到已修复候选

源级验证应在隔离环境完成,并保留原始输出。父提交的失败是已知负对照,不应进入面向用户的包;固定提交通过后,还要运行更广的 DOM 测试集。若厂商演示包、受限构建或私有测试无法复现父版,记录环境边界和缺少的证据,继续使用公开 WPT、代码顺序与产品版本完成可用判断。

测试材料也要携带自己的身份。保存 HTML 与 .headers 的哈希、WPT 提交和浏览器实际收到的响应;分别计算诊断二进制与发布二进制的哈希。这样可以避免常见实验错误:父提交二进制实际搭配了修改后的夹具,或者一次通过日志后来被归到重新构建的产物。每个字段都关闭一条明确映射,收据无需变成冗长清单。

回滚预案在发布前验证。可用回滚目标必须包含同一修复或更高安全基线,且其包、配置与数据迁移已通过冒烟。安全修复带来的兼容性问题应通过前滚小版本、功能隔离或切换到另一已修复构建解决。把父提交或旧稳定包重新设为自动回滚目标,会在下一次故障中恢复已知漏洞。

6 调查沿状态变化取证,关单沿源码到进程逐层确认

6.1 一次相关故障需要版本、生命周期和树关系三条时间线

调查 renderer 崩溃时,第一条时间线记录部署:安装包何时落地、浏览器何时重启、旧进程何时退出、页面由哪个进程处理。第二条记录网页生命周期:iframe 创建与连接、祖先移除、unload/pagehide 执行、外层 append 恢复。第三条记录节点关系:node1 在准备前、回调中和低层插入前的 parentNode。三条线对齐后,才能判断崩溃发生在漏洞窗口、测试夹具问题或已经修复后的另一种缺陷中。

诊断构建可以在共享复核与 InsertNodeVector() 前记录候选数量、节点类型、父节点存在性和目标容器类型,不需要保存页面正文或用户数据。生产遥测应优先记录模块版本、异常代码、进程角色和崩溃频次,并遵守隐私最小化。对单次崩溃的关联结论需要源版本与时序支持;一条含 ContainerNode 的栈、一个出现 iframe 的页面、一个 High CVE 标签都不能单独完成归因。

如果资产在 7 月 8 日前处理过不受信任内容,版本暴露窗口可以从旧进程启动时间持续到其实际退出时间。安装新包但保留已打开浏览器会延长窗口;VDI 快照与自动恢复还能让旧进程状态跨越维护期。关单时保存的活动进程清单既是当前证据,也能为日后事件回溯提供时间边界。

威胁狩猎可关注旧 renderer 的异常退出、同一站点触发的重复崩溃、更新后异常回退,以及嵌入式应用访问陌生内容的记录。公开证据没有提供稳定载荷字节、请求路径或域名集合,因此狩猎查询应标为行为与暴露面线索。命中后进入版本、页面与崩溃取证;未命中仍需完成升级。

更新程序替换二进制或符号之前,应先保存原始崩溃材料。合格证据包包含 dump、模块标识、二进制哈希、符号服务器身份、renderer 命令行、进程启动时间和更新代理事件日志。在策略允许时,可保存来源、响应头、导航时序,以及经过隐私复核的脚本或 DOM 快照,避免采集无关会话数据。符号化必须使用崩溃模块对应的符号,不能直接套用当前已安装浏览器。这个顺序既防止紧急升级后历史崩溃失去可读性,也能把过去暴露与当前资产状态分开。

调查时还要保存站点隔离上下文。renderer 按浏览器策略可能承载一个或多个 frame,崩溃进程中的 URL 集合也可能不同于用户看到的顶层地址。记录 frame 来源、进程 ID、导航转换,以及共享该进程的扩展或应用内容,有助于找出交付生命周期脚本的内容路径,同时避免把同进程中的其他页面直接写成因果结论。

6.2 最终结论是一个可验证的状态集合

CVE-2026-15123 的技术结论很具体:多节点准备中的同步 iframe 生命周期回调可以给候选节点设置新父节点;父提交的 Document 提前返回绕过回调后的共享结构复核;低层插入继续依赖候选无父节点的旧前提。提交 cb26b6a1... 把复核移动到分支之前,从控制流上覆盖 Document 与普通容器路线。完整 WPT 由 crashtest HTML 和 Permissions-Policy: unload=* 响应头组成,预期结果是 renderer 存活。

产品结论同样明确:常规 Chrome 资产应运行厂商当前稳定版,历史最低安全构建按平台读取;下游浏览器和嵌入式运行时必须提供自己的覆盖证明;LTS-144 的公开回移在复核日尚未合并,使用者需要供应商说明、换通道或隔离措施。部署完成、旧进程退出、回归通过、回滚目标仍安全,四项同时成立后才能关闭变更。

仍需持续跟踪的公开未知量有三项:LTS-144 评审何时合并并进入产品包,各 Chromium 下游何时发布可追溯修复,以及厂商是否更新在野利用状态。这些未知量不会推迟已经可执行的升级。它们各自有明确所有者、证据和退出条件:Gerrit 的合并提交、供应商发布说明与活动进程版本、Chrome/CVE 的利用状态更新。

对内核维护者,这起漏洞留下的工程要求是把“可执行脚本”视为结构结论的失效点,并用回调后的检查支配所有消费者分支。对防守团队,要求更直接:找到真正加载 Blink 的每个运行时,把修复绑定到活动进程,验证完整上游回归,并让自动回滚远离漏洞基线。做到这些,风险状态才从“已发公告”转为“已在本组织中消除”。

研究记录

7证据、对象与来源

下面保留本文实际使用的标识、时间和原始材料,便于继续调查。

7.1研究对象

报告涉及的产品、行为者、技术、受影响对象和控制点。

漏洞CVE-2026-15123

Chromium DOM 多节点插入期间的同步回入

上游修复cb26b6a1eb7999001e771a07944d4cb0e377341c

共享结构复核移动到 Document 专用分支之前

父提交53096e81cb3220c0a1ebf0a4b0115a1a4207ca10

Document 提前返回仍位于共享复核之前

代码评审7963938

Chromium 主线位置 #1650442

关键函数ContainerNode::RecheckNodeInsertionStructuralPrereq

重新读取候选父节点、Document 组成、祖先链与引用子节点

回归dom/nodes/crashtests/multiple-append-mutated-in-unload-document.https.html

iframe 生命周期回调重新挂载已准备候选

伴随响应头Permissions-Policy: unload=*

完整 WPT 触发条件

历史稳定构建150.0.7871.114 / 150.0.7871.115

2026 年 7 月 8 日按平台发布的 Chrome 桌面安全更新

7.2事件时间

  1. Google 收到报告

    Google 记录最初报告。

  2. 修复进入 Chromium 主线并同步到 WPT

    提交 cb26b6a1eb79 先调整共享结构复核与 Document 分支顺序;次日,41 行 crashtest 与同名 .headers 文件进入 WPT 固定提交。

  3. Chrome 发布桌面稳定版安全更新

    CVE-2026-15123 以高危 DOM 漏洞发布,安全构建按平台区分。

  4. 分支与产品状态复核

    M148、M149、M150 回移已合并;M144-LTS 评审仍为 NEW。

7.3来源与材料

  1. Chrome 2026 年 7 月 8 日桌面稳定版安全更新https://chromereleases.googleblog.com/2026/07/stable-channel-update-for-desktop_01162222768.html
  2. Chrome 2026 年 7 月 21 日桌面稳定版更新https://chromereleases.googleblog.com/2026/07/stable-channel-update-for-desktop_0256605430.html
  3. ChromeOS LTS-144 2026 年 7 月 8 日更新https://chromereleases.googleblog.com/2026/07/long-term-support-channel-update-for.html
  4. ChromeOS 2026 年 7 月 21 日 Stable、LTC 与 LTS 通道状态https://chromereleases.googleblog.com/2026/07/
  5. NVD CVE-2026-15123https://nvd.nist.gov/vuln/detail/CVE-2026-15123
  6. CVE-2026-15123 记录https://www.cve.org/CVERecord?id=CVE-2026-15123
  7. 父提交 ContainerNode 第 244—341 行https://chromium.googlesource.com/chromium/src/+/53096e81cb3220c0a1ebf0a4b0115a1a4207ca10/third_party/blink/renderer/core/dom/container_node.cc#244
  8. 修复提交 ContainerNode 第 277—298 行https://chromium.googlesource.com/chromium/src/+/cb26b6a1eb7999001e771a07944d4cb0e377341c/third_party/blink/renderer/core/dom/container_node.cc#277
  9. 修复提交 Node 多节点转换第 915—996 行https://chromium.googlesource.com/chromium/src/+/cb26b6a1eb7999001e771a07944d4cb0e377341c/third_party/blink/renderer/core/dom/node.cc#915
  10. Chromium 主线评审 7963938https://chromium-review.googlesource.com/c/chromium/src/+/7963938
  11. M148 回移评审 8020702https://chromium-review.googlesource.com/c/chromium/src/+/8020702
  12. M149 回移评审 8031406https://chromium-review.googlesource.com/c/chromium/src/+/8031406
  13. M150 回移评审 8020722https://chromium-review.googlesource.com/c/chromium/src/+/8020722
  14. M144-LTS 待合并评审 8139164https://chromium-review.googlesource.com/c/chromium/src/+/8139164
  15. Chromium 固定提交中的完整 crashtesthttps://chromium.googlesource.com/chromium/src/+/cb26b6a1eb7999001e771a07944d4cb0e377341c/third_party/blink/web_tests/external/wpt/dom/nodes/crashtests/multiple-append-mutated-in-unload-document.https.html#1
  16. WPT 固定提交中的 41 行主文件https://chromium.googlesource.com/external/github.com/web-platform-tests/wpt/+/bb2448912693c0a7239a549ad4e84aebcfbc4ebf/dom/nodes/crashtests/multiple-append-mutated-in-unload-document.https.html#1
  17. WPT 固定提交中的伴随响应头文件https://chromium.googlesource.com/external/github.com/web-platform-tests/wpt/+/bb2448912693c0a7239a549ad4e84aebcfbc4ebf/dom/nodes/crashtests/multiple-append-mutated-in-unload-document.https.html.headers#1
  18. WHATWG DOM ParentNode.append()https://dom.spec.whatwg.org/#dom-parentnode-append
  19. WHATWG DOM 节点与字符串转换算法https://dom.spec.whatwg.org/#concept-node-convert
  20. WHATWG DOM 插入前有效性检查https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity