六天、四万美元算力:一条 AI 辅助链如何穿透 Chrome 沙箱

·9 分钟阅读·Evergreen Tools Team

2026 年 10 月 13 日,XBOW 宣布其平台获得谷歌 Chrome 漏洞奖励计划(VRP)25 万美元奖金——按它的说法,这是谷歌 2026 年规则下第一笔「完整利用链」奖金,也是第一次授予自动化攻击性安全平台。一位人类研究员与 XBOW 的 AI Agent 协作六天,使用了 OpenAI 的 GPT-5.6 Sol 模型,以约四万美元算力构造出一条完整的 Windows 版 Chrome 利用链。这条链用三个此前未知的漏洞跨越了两道沙箱边界,而触发方式只是加载一个网页。真正值得记住的不是漏洞数量,而是:单独看,每一个都平平无奇。

电路板特写

三段独立的漏洞,串成一条跨越两道沙箱边界的链

哪些是宣称,哪些被确认

XBOW 表示,其平台与一位安全研究员在六天内构造出一条完整的 Windows 版 Chrome 利用链,把三个此前未知的漏洞串成一次攻击,在 Chrome 沙箱之外执行代码。XBOW 通过谷歌官方项目上报了每一个漏洞;谷歌工程师复现、确认了该利用链并发布了修复;三个漏洞的公开根因报告都已存在。XBOW 声明这些漏洞从未被用于攻击 Chrome 用户,并表示会把奖金用于保护 NGO 的安全工作。该公司估计,在修复之前,这条受影响路径覆盖了约十亿运行 Windows 版 Chrome 的人。涉及的模型被点名是 OpenAI 的 GPT-5.6 Sol,算力数字是 XBOW 自己的估算,约四万美元。

# Severity triage on single findings misses chains. Ask the graph instead.
from collections import deque

# Boundaries, from least to most privileged.
BOUNDARIES = ["renderer", "v8-heap-sandbox", "browser-process", "os-user"]

FINDINGS = [
    {"id": "F-1", "component": "v8", "from": "renderer", "to": "v8-heap-sandbox",
     "needs_user_action": False},
    {"id": "F-2", "component": "webp-decoder", "from": "v8-heap-sandbox", "to": "browser-process",
     "needs_user_action": False},
    {"id": "F-3", "component": "crashpad", "from": "browser-process", "to": "os-user",
     "needs_user_action": False},
    {"id": "F-4", "component": "settings-ui", "from": "renderer", "to": "renderer",
     "needs_user_action": True},
]

def edges(findings):
    graph = {}
    for f in findings:
        if f["from"] != f["to"]:
            graph.setdefault(f["from"], []).append(f)
    return graph

def chains_to(graph, target="os-user", start="renderer"):
    queue, seen = deque([(start, [])]), set()
    while queue:
        node, path = queue.popleft()
        for edge in graph.get(node, []):
            if edge["id"] in {p["id"] for p in path}:
                continue
            new_path = path + [edge]
            if edge["to"] == target:
                yield new_path
            elif (edge["to"], len(new_path)) not in seen:
                seen.add((edge["to"], len(new_path)))
                queue.append((edge["to"], new_path))

for chain in chains_to(edges(FINDINGS)):
    print("chain:", " -> ".join(f["id"] for f in chain))

# Three findings that would each be triaged on their own compose into one
# full-chain path from page load to code running outside the sandbox.

这条链的三个阶段

第一阶段是 V8(Chrome 的 JavaScript 引擎)里的一个漏洞,让攻击者拿到了引擎自身沙箱内部的内存控制权。第二阶段是 Chrome 动态 WebP 图像解码器里的漏洞,编号 CVE-2026-85045,它冲出了那层沙箱,并产生了一次对原生内存的精确写入。第三阶段是 Chrome 崩溃处理器 Crashpad 里的漏洞,编号 CVE-2026-78952——它运行在沙箱之外,把那次写入变成了完整的代码执行。用 XBOW 的说法,结果是「一个在 Chrome 沙箱之外启动的程序,触发方式仅仅是加载一个网页」,无需下载、无需点击。三个阶段是三处不同类型的错误,落在不同组件里,在多数组织里也归不同团队负责。

# Make the boundary model explicit, then refuse findings that do not fit it.
import json

BOUNDARY_MODEL = {
    "renderer": {"hosts_untrusted_content": True, "privilege": 1},
    "v8-heap-sandbox": {"hosts_untrusted_content": True, "privilege": 1},
    "gpu": {"hosts_untrusted_content": True, "privilege": 2},
    "network-service": {"hosts_untrusted_content": True, "privilege": 1},
    "browser-process": {"hosts_untrusted_content": False, "privilege": 3},
    "os-user": {"hosts_untrusted_content": False, "privilege": 4},
}

def validate(finding, model):
    problems = []
    for side in ("from", "to"):
        if finding[side] not in model:
            problems.append("unknown boundary: " + finding[side])
    if not problems:
        privileges = (model[finding["from"]]["privilege"], model[finding["to"]]["privilege"])
        finding["privilege_gain"] = privileges[1] - privileges[0]
    return problems

finding = {"id": "F-2", "component": "webp-decoder",
           "from": "v8-heap-sandbox", "to": "browser-process"}
print(validate(finding, BOUNDARY_MODEL), finding.get("privilege_gain"))

# If your triage tooling cannot say which boundary a finding crosses,
# every finding looks like a bug in a parser and priority becomes a coin flip.
屏幕上的安全代码流

触发方式是加载一个网页,不需要下载或点击

为什么「链式组合」会击穿严重性评分

这三个漏洞单独看,都属于那种会被降级处理的发现:JavaScript 引擎沙箱内的一次内存破坏、解码器里的一次越界写、崩溃处理器上的一个内存安全问题。每一条都是真问题,但每一条距离「远程代码执行」都很远。串起来,它们就是一次完整的沙箱逃逸。XBOW 创始人兼 CEO Oege de Moor 把这点说得很直白:彼此分离、甚至可能属于低危的漏洞,如今可以被串成一条高危利用路径;而这样一条过去要花几个月才能做出的链,现在大约四万美元算力加六天就能完成。这句话讲的是分诊经济学,而不是某个具体 CVE。如果你的流水线逐条打分,它结构性地看不见「让这条新闻成立」的那件事。

# Score by reachable privilege and user interaction, not by CVSS alone.
def priority(finding, model):
    score = 0
    score += 4 * finding.get("privilege_gain", 0)
    if model[finding["from"]]["hosts_untrusted_content"]:
        score += 3          # reachable from content, not from a local attacker
    if not finding["needs_user_action"]:
        score += 3          # no click required
    if finding.get("runs_outside_sandbox"):
        score += 2
    if finding.get("component") in {"v8", "webp-decoder", "crashpad", "ipc"}:
        score += 1          # known chain ingredient
    return score

FINDINGS = [
    {"id": "F-1", "component": "v8", "privilege_gain": 0, "needs_user_action": False,
     "runs_outside_sandbox": False},
    {"id": "F-2", "component": "webp-decoder", "privilege_gain": 2, "needs_user_action": False,
     "runs_outside_sandbox": False},
    {"id": "F-3", "component": "crashpad", "privilege_gain": 1, "needs_user_action": False,
     "runs_outside_sandbox": True},
    {"id": "F-4", "component": "settings-ui", "privilege_gain": 0, "needs_user_action": True,
     "runs_outside_sandbox": False},
]

for f in sorted(FINDINGS, key=lambda f: -priority(f, BOUNDARY_MODEL)):
    print(priority(f, BOUNDARY_MODEL), f["id"], f["component"])

# The same three lines that look unremarkable alone come out on top together.

防御方要算的是同一笔账

防御侧的读法形状相同。如果攻击者能又快又便宜地组合小漏洞,那防御者的任务就不是「找到那个可利用的漏洞」,而是在一堆发现里找出「那条可利用的路径」,并且要用接近的速度完成。这指向三个具体改动。第一,把边界显式建模,让每一条发现都能说明它跨越了哪条边界、朝哪个方向跨越。第二,按可达权限与所需用户交互来打分,而不是孤立地看 CVSS。第三,把接收不受信任输入的组件、以及任何运行在沙箱之外的东西,划成独立的补丁通道,并给更短的 SLA——因为链需要的就是这些环节。这些建议都不新,新的是无视它们的代价。

# Components that take untrusted input need a shorter SLA than UI code.
import json
from datetime import date, timedelta

SLA = {
    "untrusted-input-parsers": 7,
    "sandbox-helpers": 7,
    "crash-handling": 14,
    "ui": 90,
}

COMPONENT_CLASS = {
    "v8": "untrusted-input-parsers",
    "webp-decoder": "untrusted-input-parsers",
    "pdfium": "untrusted-input-parsers",
    "crashpad": "crash-handling",
    "settings-ui": "ui",
}

def due_dates(findings, disclosure=date(2026, 10, 13)):
    plan = []
    for f in findings:
        klass = COMPONENT_CLASS.get(f["component"], "ui")
        plan.append({"id": f["id"], "component": f["component"],
                     "class": klass, "due": str(disclosure + timedelta(days=SLA[klass]))})
    return plan

print(json.dumps(due_dates([{"id": "F-2", "component": "webp-decoder"},
                            {"id": "F-3", "component": "crashpad"}]), indent=2))

# The decoder and the crash handler are the two links that make the chain work.
# Neither is user-facing, and neither is usually on the fast lane.
锁与加密概念图

沙箱的作用不是让漏洞消失,而是让它们更难组合

这周就能落地的五件事

五件事一周内能做完。第一,为你自己发布的浏览器、办公套件或 Agent 运行时画出边界模型,并且把它写成数据,而不是一张图。第二,给每条发现加一个字段,写明它跨越哪条边界。第三,队列排序先把「权限提升幅度」放在第一位。第四,把不受信任输入的解析器、沙箱辅助组件与崩溃处理器放进七天 SLA,并且把它和「UI 代码 90 天」写在同一份文档里,让差异对每一个争论优先级的人都可见。第五,核实你的用户是否真的在已修复的版本上——源码修好,对还在跑上季度构建的人没有任何帮助,而这个缺口用一份 user-agent 分布和一个版本下限就能量出来。

# The economics are the argument. Compute the attacker's cost, then yours.
CHAIN = {
    "bugs_required": 3,
    "days": 6,
    "compute_usd": 40000,
    "researcher_days": 6,
    "affected_users": 1_000_000_000,
}

BOUNTY = {"full_chain": 250000, "single_rce": 45000, "sandbox_escape": 25000}

def attacker_model(chain, attempts_per_bug=8):
    # What it costs to find a chain if each bug needs several attempts.
    compute = chain["compute_usd"] * attempts_per_bug
    return {
        "compute_usd": compute,
        "per_user_fraction_of_a_cent": round(compute / chain["affected_users"] * 100, 2),
        "cheaper_than_full_chain_bounty": compute < BOUNTY["full_chain"],
    }

print(attacker_model(CHAIN))

# That is the whole argument for automating triage. When a high-severity path
# costs less to construct than the bounty for reporting it, defenders cannot
# keep ranking findings one at a time, by hand, once a month.

哪些还没有被证明

这是一份厂商公告,而这家厂商主张的是「自动化攻击就是最好的防御」——一个它能从中获利的位置。算力数字是 XBOW 自己的估算。谷歌确认并修复了漏洞,但没有为这套叙事、时间线或成本背书。25 万美元是有分量的,但它也是由项目规则定义的、专门针对 2026 年规则下「完整链」的金额,并不等于漏洞利用的普遍价格。请把这件事读成关于「速度」的信号,而不是基准测试;要带走的是结构性教训——小漏洞会组合——而不是营销那一层。

📌 常见问题 FAQ

XBOW 宣布了什么?

其平台获得谷歌 Chrome 漏洞奖励计划 25 万美元奖金,用于一条完整的 Chrome 利用链;按它的说法,这是谷歌 2026 年规则下第一笔完整链奖金,也是首次授予自动化攻击性安全平台。一位研究员与 XBOW 的 AI Agent 协作六天完成。

这条链由哪些漏洞组成?

V8(Chrome 的 JavaScript 引擎)中的一个漏洞,用于在引擎沙箱内取得内存控制;Chrome 动态 WebP 图像解码器中的 CVE-2026-85045,用于冲出该沙箱;以及运行在沙箱之外的崩溃处理器 Crashpad 中的 CVE-2026-78952,把结果变成完整代码执行。

用户需要点击或下载什么吗?

不需要。按 XBOW 的说法,这条链通过加载一个网页即可触发,无需用户下载或点击。在修复之前,这一类别的问题位于约十亿运行 Windows 版 Chrome 用户的路径上。

这个利用链在流传吗?

XBOW 称已通过谷歌官方项目上报全部漏洞,谷歌复现并确认了利用链、发布了修复,且这些漏洞从未被用于攻击 Chrome 用户。三个漏洞的公开根因报告均已提供。

为什么「链式组合」对漏洞分诊很重要?

因为单独看属于低危的发现可以组合成一次完整逃逸,而逐条打分看不见这种组合。应当按「跨越的权限边界」以及「是否需要用户交互」来排序,并给不受信任输入的解析器与沙箱辅助组件更短的修复期限。