CVE-2026-11073
Overview
Files Changed
third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
Patch
From dd6b2a8de1b4a30b28865c3e27255e2db98492e3 Mon Sep 17 00:00:00 2001 From: Andrey Kosyakov <[email protected]> Date: Tue, 14 Apr 2026 12:50:14 -0700 Subject: [PATCH] Perform detach check when processing PassAsSpan arguments of NADC calls too Bug: 499365904 Change-Id: I957efef97bee1417b7e13d2c360180a68028bfbc Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7746207 Reviewed-by: Kenneth Russell <[email protected]> Commit-Queue: Andrey Kosyakov <[email protected]> Cr-Commit-Position: refs/heads/main@{#1614674} --- diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py index de414fa..046be14 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py @@ -2488,7 +2488,9 @@ body.register_code_symbol( S( "kPerformDetachCheckFlag", - "constexpr auto kPerformDetachCheckFlag = PassAsSpanMarkerBase::Flags::kNone;" + # TODO(caseq): figure out if it makes sense to skip it when we can. + # See https://crbug.com/499365904 for details. + "constexpr auto kPerformDetachCheckFlag = PassAsSpanMarkerBase::Flags::kPerformDetachCheck;" )) bind_callback_local_vars(body, cg_context)
Original Bug Report
Use-After-Free Read in WebGL multi-draw via ArrayBuffer detachment
Flapjack, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports without the security team.
Overview: A potential Use-After-Free (UAF) read exists in WebGL multi-draw extensions due to bypassed ArrayBuffer detachment checks in generated NoAllocDirectCall (NADC) stubs. An attacker can pass a malicious sequence to execute JavaScript during argument conversion, detaching an earlier argument’s buffer and passing a dangling pointer to the GPU.
Affected files:
third_party/blink/renderer/modules/webgl/webgl_multi_draw.idlthird_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.idlthird_party/blink/renderer/modules/webgl/webgl_multi_draw.ccthird_party/blink/renderer/modules/webgl/webgl_multi_draw_instanced_base_vertex_base_instance.cc
Estimated timestamp from git blame: 2026-03-18
Summary
A potential Use-After-Free (UAF) read vulnerability exists in WebGL multi-draw extensions (e.g., WEBGL_multi_draw). The issue stems from an incorrect assumption in Blink’s bindings generator for functions annotated with [NoAllocDirectCall] (NADC). The generator disables ArrayBuffer detachment checks for [PassAsSpan] arguments, incorrectly assuming JavaScript cannot execute during the argument conversion phase. However, because the IDL types allow sequences, converting a later argument can invoke a JavaScript iterator, detaching the buffer of an earlier argument and leading to a UAF read when the WebGL implementation executes.
Technical Details
- Methods like
multiDrawArraysWEBGLuse the[NoAllocDirectCall]attribute for optimization and acceptInt32Listarguments (firstsList,countsList), which are defined as[PassAsSpan] (Int32Array or sequence<GLint>). - In
third_party/blink/renderer/bindings/scripts/bind_gen/interface.py, the NADC stub generator hardcodesconstexpr auto kPerformDetachCheckFlag = PassAsSpanMarkerBase::Flags::kNone;. This completely compiles out theWasDetached()check insideByteSpanWithInlineStorage::as_span(). - The NADC signature takes
v8::Local<v8::Value>for these arguments. WhenNativeValueTraits<PassAsSpan<...>>::ArgumentValueconverts the first argument (firstsList), it extracts the raw pointer to theArrayBufferbacking store. - When converting the second argument (
countsList), if the attacker provides a sequence (an iterable object), the fallback pathNativeValueTraits<IDLSequence<...>>::ArgumentValueis hit. This iterates the sequence using V8 APIs, executing synchronous JavaScript (e.g., a custom iterator). - If this JavaScript detaches the
ArrayBufferoffirstsList(e.g., viapostMessage), the backing store is immediately freed. - Because the detachment check is disabled (
kPerformDetachCheckFlag == kNone), the dangling raw pointer is cast to abase::spanand passed into the Blink implementation. - Inside
gpu/command_buffer/client/transfer_buffer_cmd_copy_helpers.h, amemcpyreads from this dangling pointer into a shared memory transfer buffer, resulting in a UAF Read.
MiraclePtr (BackupRefPtr) is explicitly disabled for the ArrayBuffer partition, meaning it offers no protection against this UAF.
Potential Steps to Trigger
Note: These are suggested steps; a working Proof of Concept has not yet been executed by our tooling.
- An attacker sets up a WebGL context and enables the
WEBGL_multi_drawextension. - The attacker creates an
Int32Array(backed by anArrayBuffer) for thefirstsListargument. - The attacker creates a custom JavaScript iterable object (e.g., an array with a modified
Symbol.iterator) for thecountsListargument. - Inside the custom iterator, the attacker places code to call
postMessage()ortransfer()on theArrayBuffercreated in Step 2, detaching it. - The attacker calls
ext.multiDrawArraysWEBGL(mode, firstsList, 0, countsList, 0, drawcount). - The Fast API NADC stub begins processing, extracts the pointer for
firstsList, then evaluatescountsList. The malicious iterator executes, freeingfirstsList’s memory. - The GPU command buffer copies the memory from the dangling pointer, leaking heap memory from the ArrayBuffer partition.
Affected Methods
multiDrawArraysWEBGLmultiDrawElementsWEBGLmultiDrawArraysInstancedWEBGLmultiDrawElementsInstancedWEBGLmultiDrawArraysInstancedBaseInstanceWEBGLmultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL
Suggested Fix
Update third_party/blink/renderer/bindings/scripts/bind_gen/interface.py. Do not force kPerformDetachCheckFlag to kNone for NADC stubs when processing PassAsSpan arguments. The detachment check is extremely cheap (a boolean flag check) and must be maintained as long as sequence fallback conversion (which can execute JS) is possible in Fast API calls.
Alternatively, enforce that [PassAsSpan] arguments on [NoAllocDirectCall] methods strictly accept TypedArray objects and reject sequences prior to evaluation.
Evaluated with Chrome root at commit: 09ec9e7cc4d24823d20b6d37cf3d282734f6bf0f
Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.