High chrome Uninitialized Memory 📄 Reporter bug report 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUninitialized Use in GPU
DescriptionUninitialized Use in GPU
ComponentGPU
Bug ClassUninitialized Memory
Tracker522840723
Fix commit92b7a3ad4869 (chromium/src) +1/-0
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-23

Files Changed

  • gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
From 92b7a3ad4869e940d79019996d0751f739e1a842 Mon Sep 17 00:00:00 2001
From: Brandon Jones <bajones@chromium.org>
Date: Fri, 12 Jun 2026 10:00:56 -0700
Subject: [PATCH] Clear PIXEL_PACK_BUFFER in CopyTextureCHROMIUM

One Android path in CopyTextureCHROMIUM uses a glReadPixels call
to a client buffer, but doesn't clear the PIXEL_PACK_BUFFER
before doing the read. If the page sets the PIXEL_PACK_BUFFER
in a WebGL 2 context prior to this method being called it could
interfere with the data being read, leading the client buffer to
potentially contain uninitialized memory.

This change ensures the PIXEL_PACK_BUFFER is always set to 0
before performing the client read.

Fixed: 522840723
Change-Id: I95c3ad176a2759b490b0b36555c186489fe9153d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7927868
Commit-Queue: Brandon Jones <bajones@chromium.org>
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1646051}
---

diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
index 1c76f7eb..fda1e42 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
+++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -716,6 +716,7 @@
     // GLCopyTextureCHROMIUMES3Test.FormatCombinations in gl_tests. This is seen
     // on Nexus 5 but not Nexus 4. Read pixels to client memory, then upload to
     // pixel unpack buffer with glBufferData.
+    glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
     auto pixels = base::HeapArray<uint8_t>::Uninit(pixel_num * 4);
     glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
     auto data = base::HeapArray<float>::Uninit(pixel_num * 3);
Loading diff…

Original Bug Report

reported by rj...@google.com

Potential GPU Information Leak via uninitialized fallback buffer in CopyTextureCHROMIUM on Android

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. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: The Android software fallback path for CopyTextureCHROMIUM allocates an uninitialized heap array for reading pixels. By keeping a Pixel Buffer Object (PBO) bound to GL_PIXEL_PACK_BUFFER, an attacker can reliably cause the glReadPixels call to fail, leaving the array uninitialized. This stale GPU process heap memory is then uploaded to a texture, leading to a cross-origin information leak.

Affected files:

  • gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc

Estimated timestamp from git blame: 2017-03-30

Overview

A vulnerability exists in the Android software fallback path of CopyTextureCHROMIUM that could allow a malicious webpage to leak uninitialized memory from the GPU process heap. By manipulating WebGL state, an attacker can force a readback failure, causing stale heap data to be uploaded to an attacker-controlled texture.

Root Cause

The issue lies in gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc, specifically within PrepareUnpackBuffer. When copying to a destination internal format that requires conversion, such as GL_RGB9_E5, the implementation falls back to CopyTextureMethod::DRAW_AND_READBACK.

On Android, when format == GL_RGB and type == GL_FLOAT, PrepareUnpackBuffer allocates uninitialized memory using base::HeapArray<uint8_t>::Uninit and attempts to populate it using glReadPixels:

  if (format == GL_RGB && type == GL_FLOAT) {
#if BUILDFLAG(IS_ANDROID)
    auto pixels = base::HeapArray<uint8_t>::Uninit(pixel_num * 4);
    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
    // ...

The vulnerability occurs because the code fails to unbind the GL_PIXEL_PACK_BUFFER target before calling glReadPixels (unlike the non-Android fallback path, which explicitly binds a different pack buffer).

If an attacker binds a WebGL Pixel Buffer Object (PBO) to gl.PIXEL_PACK_BUFFER immediately before issuing a texture copy command, the OpenGL driver interprets the pixels.data() host pointer as a large integer offset into the bound PBO. Since this offset typically exceeds the bounds of the PBO, the driver safely rejects the operation with a GL_INVALID_OPERATION error. Consequently, the glReadPixels call writes no data, and the pixels array retains uninitialized GPU heap memory.

The uninitialized memory is then converted to floating-point format and uploaded to a local GL_PIXEL_UNPACK_BUFFER, which is subsequently uploaded to the final destination texture via glTexSubImage2D.

Potential Attack Steps

Note: These are suggested steps; our tooling has not executed a proof of concept.

  1. Initialize a WebGL 2.0 context, which provides access to GL_RGB9_E5 textures and PBOs.
  2. Create a texture and configure it with the gl.RGB9_E5 internal format.
  3. Create a WebGLBuffer and bind it to gl.PIXEL_PACK_BUFFER.
  4. Allocate a very small size for this buffer (e.g., 1 byte) using gl.bufferData to ensure any host-pointer offset will trigger an out-of-bounds error.
  5. Prepare an HTMLVideoElement to serve as the source for the upload.
  6. Call gl.texSubImage2D targeting the gl.RGB9_E5 texture, passing the video element. This triggers the DRAW_AND_READBACK path in the GPU process.
  7. The GPU process allocates uninitialized heap memory. Due to the bound pack buffer, glReadPixels fails, and the uninitialized memory is written into the GL_RGB9_E5 texture.
  8. Because GL_RGB9_E5 cannot be read directly via gl.readPixels, compile a WebGL shader that samples from the GL_RGB9_E5 texture and renders it into a standard color-renderable texture (e.g., gl.RGBA8).
  9. Call gl.readPixels on the standard texture to read the leaked GPU memory back to JavaScript, bypassing Site Isolation.

Proposed Fix

Explicitly unbind the GL_PIXEL_PACK_BUFFER target before invoking glReadPixels in the Android fallback path to prevent the driver from interpreting the host pointer as a PBO offset.

    glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());

Additionally, consider using zero-initialized memory (base::HeapArray<uint8_t>::WithSize) instead of Uninit when reading back pixel data to provide a robust defense-in-depth against similar uninitialized memory leaks.

Evaluated with Chrome root at commit: 2155cb00003ec35716a76ed3246eae995f87b7ff


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.

View on issue tracker