CVE-2026-18005
Overview
Files Changed
third_party/blink/renderer/modules/xr/xr_cube_map.cc
Patch
From 4d7d34c407727c31e3778c91a46e137336a6b2bf Mon Sep 17 00:00:00 2001
From: Brandon Jones <bajones@chromium.org>
Date: Wed, 10 Jun 2026 15:54:57 -0700
Subject: [PATCH] Unset PIXEL_UNPACK_BUFFER before updating XR cubemap
Ensures that the PIXEL_UNPACK_BUFFER is not set prior to updating
the XR environment cubemap. This operation uses TexImage2D calls,
which having a set PIXEL_UNPACK_BUFFER interferes with. Buffer is
restored at the end of the call.
Fixed: 522300211
Change-Id: I4a35efabb1bf5c8bad8da195d0aef8f31b37e866
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7920431
Commit-Queue: Brandon Jones <bajones@chromium.org>
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1644942}
---
diff --git a/third_party/blink/renderer/modules/xr/xr_cube_map.cc b/third_party/blink/renderer/modules/xr/xr_cube_map.cc
index d13bc79e..6e75abe 100644
--- a/third_party/blink/renderer/modules/xr/xr_cube_map.cc
+++ b/third_party/blink/renderer/modules/xr/xr_cube_map.cc
@@ -101,6 +101,13 @@
ScopedUnpackParametersResetRestore unpack_params(context);
auto* gl = context->ContextGL();
+
+ // Ensure the PIXEL_UNPACK_BUFFER is not set, which would otherwise interfere
+ // with the TexImage2D operations.
+ if (context->IsWebGL2()) {
+ gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+ }
+
texture->SetTarget(GL_TEXTURE_CUBE_MAP);
gl->BindTexture(GL_TEXTURE_CUBE_MAP, texture->Object());
@@ -153,6 +160,9 @@
DrawingBuffer::Client* client = static_cast<DrawingBuffer::Client*>(context);
client->DrawingBufferClientRestoreTextureCubeMapBinding();
+ if (context->IsWebGL2()) {
+ client->DrawingBufferClientRestorePixelUnpackBufferBinding();
+ }
// Debug check for success
DCHECK(gl->GetError() == GL_NO_ERROR);
Original Bug Report
Low 32-bit renderer heap pointer leak in XRCubeMap::updateWebGLEnvironmentCube
Project Fortify, 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. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: A potential vulnerability in Blink’s WebXR implementation can allow a malicious page to leak the lower 32 bits of a renderer-process heap address. The issue occurs because XRCubeMap::updateWebGLEnvironmentCube passes raw heap pointers to TexImage2D without unbinding the active GL_PIXEL_UNPACK_BUFFER. When a PBO is bound, the client-side GLES2 implementation interprets these pointers as byte offsets, allowing an attacker to determine their values.
Affected files:
third_party/blink/renderer/modules/xr/xr_cube_map.ccthird_party/blink/renderer/modules/xr/xr_webgl_binding.cc
Estimated timestamp from git blame: 2020-01-16
Description
A potential information leak vulnerability exists in Blink’s WebXR implementation where the lower 32 bits of a renderer process heap address can be disclosed.
Root Cause
When a WebGL2 page requests an environmental reflection cubemap, Blink calls XRCubeMap::updateWebGLEnvironmentCube in third_party/blink/renderer/modules/xr/xr_cube_map.cc to upload the cubemap image data to a texture.
The function instantiates ScopedUnpackParametersResetRestore to temporarily reset the WebGL unpack parameters. However, this helper only resets the pixel store state (like GL_UNPACK_ALIGNMENT and GL_UNPACK_ROW_LENGTH); it does not unbind the client-bound pixel unpack buffer (GL_PIXEL_UNPACK_BUFFER).
When a GL_PIXEL_UNPACK_BUFFER remains bound, the underlying command buffer client in GLES2Implementation::TexImage2D (gpu/command_buffer/client/gles2_implementation.cc) treats the pixels data pointer as an offset within the PBO rather than a client-side CPU pointer. It coerces the pointer using ToGLuint(pixels) which truncates the 64-bit heap address to its lower 32 bits:
inline uint32_t ToGLuint(const void* ptr) {
return static_cast<uint32_t>(reinterpret_cast<size_t>(ptr));
}
This coerced 32-bit offset is then transmitted to the GPU process via IPC.
Because both code branches in updateWebGLEnvironmentCube pass raw renderer-heap pointers—either a newly-allocated temporary conversion vector (sRGB.data()) or the persistent backing stores of the cubemap image spans (image.data())—the low 32 bits of these PartitionAlloc heap addresses are serialized and treated as a PBO offset.
Potential Attack Scenario
An attacker could potentially execute the following steps to exploit this leak:
- Initialize a WebGL2 context and bind a client-side Pixel Buffer Object (PBO) to the
GL_PIXEL_UNPACK_BUFFERtarget viagl.bindBuffer(). - Obtain an immersive-AR session with the
light-estimationfeature enabled on a supported device (e.g., Android with ARCore) and request a light probe. - Retrieve the environmental cubemap texture by calling
binding.getReflectionCubeMap(lightProbe). - Systematically binary search the offset value by varying the allocated size of the PBO and monitoring for
GL_INVALID_OPERATIONviagl.getError()(triggered whenoffset + image_size > pbo_size). Alternatively, the attacker could read back the uploaded texture data to determine the byte layout. - Recover the lower 32 bits of the heap pointer, effectively bypassing/weakening ASLR for the renderer process.
Note: Since our automated tooling lacks the capability to execute code or build functional exploits on target hardware, these steps are suggested and theoretical.
Suggested Fix
To resolve this issue, ensure that any bound GL_PIXEL_UNPACK_BUFFER is temporarily unbound before invoking TexImage2D inside XRCubeMap::updateWebGLEnvironmentCube, and restored afterward. This can be accomplished by expanding ScopedUnpackParametersResetRestore to handle the PIXEL_UNPACK_BUFFER binding or by adding an explicit unbind scope in updateWebGLEnvironmentCube:
// Temporarily unbind pixel unpack buffer if bound
if (context->ValdiateUnpackParameters(...)) {
gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}
Evaluated with Chrome root at commit: b2fea2e31df308d0f04e4ae47def4c4f939ee141
Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:
- If you are familiar with the severity guidelines, you may adjust the severity.
- If this is a false positive, and there’s no work to be done, please close as WAI.
- If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.
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.