b56c9d4512fc4a0ea800f7577cf77eff7680e0fc [WebGLOnWebGPU] Disable ANGLE client-side array handling
Triage note: Configures the ANGLE context with CLIENT_ARRAYS disabled, BIND_GENERATES_RESOURCE off, and robust resource init on. Real memory-safety hardening, but WebGLOnWebGPU is experimental and flag-gated (not default), so watch/not-exploitable-by-default.
The bug at a glance
The commit metadata classifies this OOB-read as medium (score 3.8, CVSS 6.5) and marks it non-directly-exploitable. That is the honest reading of the diff. The change does not fix a demonstrated arbitrary-read primitive with attacker-controlled pointer; it hardens the ANGLE context that the experimental WebGLOnWebGPU backend spins up so that a class of interpretation bugs (attribute offsets treated as client-side pointers) is structurally impossible, plus it turns on robust resource initialization to prevent uninitialized GPU/host memory from leaking back to script. Because WebGLOnWebGPU is an experimental/off-by-default backend rather than the shipping WebGL path, real-world reach is gated behind a flag, which caps severity below high. But the primitive it forecloses (offset->pointer semantics under WebGL, which is fully scriptable) is genuinely dangerous where reachable, so this is a legitimate watch-tier security hardening, not noise. Medium is defensible; I would not push it higher without evidence the backend was reachable in a default config.
WebGL lets script set vertex attribute pointers via glVertexAttribPointer. In classic desktop GL, the last argument is either a byte offset into the currently bound ARRAY_BUFFER (buffer-object mode) or, when no buffer is bound, a raw CPU pointer into client memory (client-array mode). WebGL forbids client arrays: everything must go through buffer objects, and the ‘pointer’ is always an offset. The angle here is that the WebGLOnWebGPU shim creates its own internal ANGLE GL context and, by omission, left ANGLE’s client-array handling enabled. If ANGLE then interpreted an attribute ‘offset’ with client-side pointer semantics, an attacker-supplied integer offset could be treated as an address in the GPU process, yielding an out-of-bounds or effectively arbitrary read at draw time — all driven from ordinary WebGL JS.
Root cause
eglCreateContext is called with an EGL attribute list. The patch inserts three attribute/value pairs before EGL_NONE. EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE=EGL_FALSE tells ANGLE to reject/ignore client-side vertex arrays, forcing every vertex attribute to resolve as an offset into a bound buffer object; this is precisely what removes the offset-as-pointer interpretation. EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM=EGL_FALSE disables the legacy GL behavior where binding an unknown name (e.g. glBindBuffer to an id never created) implicitly creates the resource; with it false, binding an unrecognized name is an error, which keeps the buffer/name namespace explicit and prevents the shim from operating on silently-conjured, unvalidated resources. EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE=EGL_TRUE makes ANGLE zero-initialize newly allocated textures/buffers/renderbuffers so that reads of not-yet-written regions return zeros instead of stale host or GPU memory, closing an info-leak channel. All three are context-creation-time flags; there is no logic change elsewhere. The security value is that the WebGLOnWebGPU context is now created with the same conservative, robust semantics the mainline command-buffer WebGL path already relies on.
Key code
Three ANGLE context-creation flags added to the WebGLOnWebGPU EGL attribute list
EGL_FALSE,
EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE,
EGL_FALSE,
+ EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE,
+ EGL_FALSE,
+ EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM,
+ EGL_FALSE,
+ EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE,
+ EGL_TRUE,
EGL_NONE,
};
context_ = driver_egl_.fn.eglCreateContextFn(display_, EGL_NO_CONFIG_KHR,
Patch walkthrough
third_party/blink/renderer/modules/webgl/webgl_rendering_context_webgpu_base.cc— The only file changed. In the routine that constructs the ANGLE EGL context backing the WebGLOnWebGPU implementation, three key/value pairs are spliced into the EGL_CONTEXT attribute array immediately before the EGL_NONE terminator. No control flow, allocation, or draw-path code changes; the fix is entirely declarative at context creation. CLIENT_ARRAYS_ENABLED=FALSE forecloses offset-as-pointer interpretation of vertex attributes; BIND_GENERATES_RESOURCE=FALSE disables implicit resource creation on bind; ROBUST_RESOURCE_INITIALIZATION=TRUE forces zero-init of freshly allocated resources. Because these flags are consumed by ANGLE at eglCreateContext time, every subsequent GL operation issued by the shim inherits the hardened semantics for the life of the context.
Background
WebGLOnWebGPU — An experimental Blink backend that implements the WebGL API surface on top of WebGPU, using ANGLE as the GL translation frontend. It creates its own internal ANGLE GL/EGL context distinct from the mainline command-buffer WebGL path, so context-creation hardening that mainline WebGL already applies must be reapplied here explicitly.
Client-side arrays — A legacy OpenGL feature where glVertexAttribPointer’s final argument is a raw CPU pointer to vertex data when no buffer object is bound. WebGL prohibits this; all vertex data must live in buffer objects and the argument is a byte offset. If a lower layer still honors client-array semantics, an attacker-controlled offset can be misread as a pointer.
BIND_GENERATES_RESOURCE — Classic GL creates an object the first time an unused name is bound. Disabling it makes binding an unknown name an error, keeping the object namespace explicit and preventing the shim from acting on implicitly-created, unvalidated resources.
Robust resource initialization — An ANGLE feature that zero-initializes textures, buffers, and renderbuffers on allocation so that reading regions never explicitly written returns deterministic zeros rather than stale process or GPU memory — a standard defense against cross-origin/uninitialized-memory disclosure in WebGL.
Vulnerability window
- Introduction — When the WebGLOnWebGPU EGL context-creation code was written, its attribute list omitted the client-array, bind-generates-resource, and robust-init flags, so ANGLE defaulted to the more permissive legacy semantics for this context.
- Discovery — Tracked as chromium bug 472376568. Reviewed by ANGLE/WebGPU owners Corentin Wallez and Geoff Lang, indicating the risk was recognized during backend hardening rather than from an external in-the-wild report.
- Fix — Landed 2026-01-07 as main@{#1565487} by Wenxiang Qian, adding the three conservative context flags at creation time.
- Exposure window — Limited to builds where the WebGLOnWebGPU backend was reachable/enabled. As an experimental path this is narrower than shipping WebGL, which is why it stayed silent/watch-tier.
Proof of concept
No test or PoC ships with this commit; it is a context-creation flag change. An honest reproduction recipe (no exploit demonstrated): enable the WebGLOnWebGPU backend, obtain a WebGL context routed through it, then exercise vertex attribute setup — glVertexAttribPointer with a large or crafted offset while manipulating buffer bindings — and observe whether draw calls (drawArrays/drawElements) read outside the bound buffer or return stale memory (e.g. via readPixels of rendered output, or transform-feedback capture). Before the patch, the concern is that ANGLE could resolve the offset with client-pointer semantics; after, offsets are strictly buffer-relative and out-of-range access is bounded/errored. Demonstrating an actual OOB read would require the pre-patch backend and ANGLE build and is not provided here.
Exploitation
- Reach the backend — Attacker script must run in a context where WebGLOnWebGPU is the active WebGL implementation (flag/config gated). This is the primary limiter on practical exploitability.
- Set attribute offset — Call glVertexAttribPointer/vertexAttribPointer with a controlled integer ‘offset’, potentially without a well-formed bound buffer, aiming for ANGLE to treat the value under client-array/pointer semantics.
- Trigger draw — Issue a draw call so the vertex fetch dereferences the attribute source. If interpreted as a pointer/offset beyond bounds, reads pull from out-of-range or uninitialized memory.
- Exfiltrate — Route the read-back memory into observable output (rendered pixels via readPixels, transform feedback, or timing) to recover leaked bytes. Robust-init closes the uninitialized-read variant; client-array disable closes the offset-as-pointer variant.
Detection & hunting
For defenders and detection engineers:
- EGL context attributes — Audit all eglCreateContext call sites in Blink/GPU that build ANGLE contexts and confirm CLIENT_ARRAYS_ENABLED=FALSE, BIND_GENERATES_RESOURCE=FALSE, and ROBUST_RESOURCE_INITIALIZATION=TRUE are present. Their absence in any new/experimental GL backend is the fingerprint of this bug class.
- ANGLE validation errors — With the flags set, malformed binds and client-array use now emit GL errors; a spike in these from the WebGLOnWebGPU path can indicate content probing the newly-restricted semantics.
- readPixels/transform-feedback anomalies — Fuzzing signal: rendered output containing non-zero data in regions that should be zero-initialized suggests robust-init is not effective on some code path.
Audit directions
- Sibling GL backends — Any other Blink or GPU-process component that constructs an ANGLE context outside the mainline command-buffer (e.g. other WebGPU/WebGL bridges, canvas or video paths) should be checked for the same missing hardening flags.
- Vertex attribute path in WebGLOnWebGPU — Beyond context flags, review how vertexAttribPointer offsets and buffer bounds are validated in the shim itself, to confirm defense-in-depth even if a future context regresses these flags.
- Resource-init coverage — Verify robust resource initialization actually covers every resource type the shim allocates (textures, buffers, renderbuffers, FBO attachments); ANGLE robust-init has historically had per-format gaps worth confirming.