High watch CVSS 8.8 chrome UAF 📄 Reporter bug report 🔧 Commit mapped

Overview

High
Severity
8.8
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in WebGL
DescriptionUse after free in WebGL
ComponentWebGL
Bug ClassUAF
Action tierwatch — corruption primitive but gated (uncommon) — not default-reachable
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker543082390
Fix commit2b3a653dda35 (chromium/src) +5/-0
CWECWE-416 (Use-after-free)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CISA KEVNot listed
CreditedOpenAI Codex Security (amyb)
Reported2026-08-05 (per vendor advisory)
Fix landed2026-08-12 (public git)
Disclosed2026-08-18
Patch gap6 days — fix public in source before the advisory

Background

`OVR_multiview2`
a WebGL 2 extension, implemented in Blink in ovr_multiview_2.cc, that exposes framebufferTextureMultiviewOVR so a range of layers of a 2D array texture can be attached to a framebuffer for multi-view rendering.
Framebuffer attachment tracking
Blink’s WebGL layer keeps its own record of which texture is attached to which attachment point of the bound framebuffer, separate from the GPU-process state, and relies on that record to keep attached objects valid.
`ValidateFramebufferFuncParameters`
an existing WebGL2RenderingContextBase helper used by framebufferTexture2D and similar calls to check that target is a valid framebuffer binding point and attachment is a valid attachment enum before any state is changed.

Root Cause Analysis

The vulnerable path is the WebGL entry point for framebufferTextureMultiviewOVR in third_party/blink/renderer/modules/webgl/ovr_multiview_2.cc. The hunk header does not name the enclosing function, but the error strings indicate it is the extension’s framebufferTextureMultiviewOVR implementation. Before the patch, that function validated the texture layer range (ValidateTexFuncLayer) and the mip level (ValidateTexFuncLevel), but passed the caller-supplied target and attachment through without checking them. The commit message says this “could lead to resource tracking issues if an out-of-range value was given”. In other words, Blink’s attachment bookkeeping could be updated using an attachment or target value that the normal framebufferTexture2D path would reject, which leaves Blink’s view of which texture is attached out of step with reality. The advisory classes the result as a use-after-free in WebGL. The exact freed object and the dereference site are not in the diff (inferred: a texture or attachment record whose lifetime tracking went wrong because it was recorded under an invalid attachment slot).

The fix adds a call to ValidateFramebufferFuncParameters after the layer check and before the level check. On an invalid target or attachment it returns early, so the tracking code further down the function is never reached with an unvalidated value.

Key insight
The multiview attach call trusted target and attachment that every other framebuffer-attach entry point validates, so bad enums reached Blink’s attachment/resource tracking. The fix reuses the framebufferTexture2D validation (ValidateFramebufferFuncParameters) and returns early before any state is changed.

Attack Path

  1. Obtain the extension A page creates a WebGL 2 context and enables OVR_multiview2 with getExtension. This works only where the GPU/driver exposes the extension (inferred: no flag or user gesture is needed where it is supported).
  2. Pass out-of-range enums The page calls framebufferTextureMultiviewOVR with a valid texture, level and layer range but an invalid target or attachment. Before the patch, these passed every check the function made.
  3. Corrupt attachment tracking Execution continued past validation into the function’s attachment handling (not shown in the hunk). Blink recorded the texture against an attachment slot or binding that the normal paths would never accept, so its tracking no longer matched the real attachment state (inferred from the commit message).
  4. Trigger the stale reference Later WebGL operations, such as deleting the texture or framebuffer, or tearing down the context, act on the mismatched tracking state. The result is a use-after-free in the renderer (the specific freed object and sink are inferred and not shown in the patch).

Impact Assessment

The advisory describes a use-after-free in WebGL. The bug lives in Blink’s WebGL module, so ordinary web content running in the sandboxed renderer process can reach it (inferred), with the precondition that OVR_multiview2 is available on the user’s GPU/driver. Memory corruption in the renderer could plausibly lead to code execution inside the sandbox (inferred). The vendor advisory rates this high severity and does not report in-the-wild exploitation; NVD scores it CVSS 8.8.

Files Changed

  • third_party/blink/renderer/modules/webgl/ovr_multiview_2.cc

Audit Directions

  • Extension entry points that bypass core validation
    Check WebGL and WebGL 2 extension methods in third_party/blink/renderer/modules/webgl/ (for example other *Multiview*, draw-buffer and framebuffer-related extensions). Each should apply the same enum and range validation as the core API it mirrors before touching Blink-side tracking.
  • Bookkeeping keyed by caller-supplied enums
    Audit code that updates Blink-side attachment maps, binding points or object references using a GLenum taken from JavaScript. If it does not first confirm the enum belongs to the expected set, a mismatch between Blink and GPU state can lead to stale-pointer bugs.
  • Validation ordering
    Make sure every early-return validator runs before the first state mutation in WebGL setter functions, so that rejected calls can never leave partially updated tracking behind.
From 2b3a653dda35893442fbda35c6d8f89b0c683002 Mon Sep 17 00:00:00 2001
From: Brandon Jones <bajones@chromium.org>
Date: Tue, 11 Aug 2026 18:38:56 -0700
Subject: [PATCH] Validate framebufferTextureMultiviewOVR target, attachment

Previously these were being passed through unvalidated, which could
lead to resource tracking issues if an out-of-range value was
given. While the extension definitions for this method don't state
any explicit validation to perform on these values it should be
safe to assume they should be treated like values being passed to
framebufferTexture2D, and thus the same validation is reused here.

Fixed: 543082390
Change-Id: I63a172b6723e6e5a626d50583668b4dc0ca2a33a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8243727
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1677709}
---
diff --git a/third_party/blink/renderer/modules/webgl/ovr_multiview_2.cc b/third_party/blink/renderer/modules/webgl/ovr_multiview_2.cc
index 8af07167..2633c7b 100644
--- a/third_party/blink/renderer/modules/webgl/ovr_multiview_2.cc
+++ b/third_party/blink/renderer/modules/webgl/ovr_multiview_2.cc
@@ -62,6 +62,11 @@
              ->ValidateTexFuncLayer("framebufferTextureMultiviewOVR", textarget,
                                     base_view_index + num_views - 1))
       return;
+    if (!static_cast<WebGL2RenderingContextBase*>(scoped.Context())
+             ->ValidateFramebufferFuncParameters(
+                 "framebufferTextureMultiviewOVR", target, attachment)) {
+      return;
+    }
     if (!scoped.Context()->ValidateTexFuncLevel(
             "framebufferTextureMultiviewOVR", textarget, level))
       return;
Loading diff…

Original Bug Report

reported by am...@openai.com

WebGL OVR_multiview2 Oilpan Use-After-Free Enables Arbitrary Native Write

WebGL OVR_multiview2 Oilpan Use-After-Poison

As a request of https://issues.chromium.org/issues/543082387#comment4 I have re-opened this issue with a short description along with an ASAN trace.

Please note that this vulnerability is the first part of a working full sandbox-escape exploit chain we are in the process of analyzing and reporting.

I want to affirm our commitment to only report vulnerabilities for which we have strong evidence that they are exploitable. We understand you are dealing with an influx of reports and thank you for your efforts to keep Chrome secure.

Tested Version

  • Chromium 151.0.7922.0, Stable-branch ASan revision 1654411 (Linux x86_64).
  • Chromium commit: 059c884787b1bc15faa5afe5250f7d3a7e0ef64a.
  • Chrome BuildId: 5c8f91628a04675e.

The vulnerable source files are the same in Chrome 151.0.7922.76 and the vulnerability still exists in latest main.

PoC: chromium-ovr-oilpan-asan-use-after-poison.html

Root Cause

OVRMultiview2::framebufferTextureMultiviewOVR fails to validate its framebuffer attachment enum before inserting it into WebGLFramebuffer’s Oilpan HeapHashMap. Supplying the reserved hash-table key 0xffffffff causes Oilpan to skip tracing the attachment’s strong reference. A major collection poisons the unmarked attachment, and a later removal dereferences that poisoned object in WebGLFramebuffer::RemoveAttachmentInternal.

Symbolized ASan Report

Symbolized offline using the exact matching build’s bundled llvm-symbolizer and Chrome ELF. The sandboxed renderer could not launch the external symbolizer; the original warnings are retained.

=================================================================
==1==ERROR: AddressSanitizer: use-after-poison on address 0x7b9402009020 at pc 0x5642643decc5 bp 0x7ffe83b62cb0 sp 0x7ffe83b62ca8
READ of size 8 at 0x7b9402009020 thread T0 (chrome)
==1==WARNING: invalid path to external symbolizer!
==1==WARNING: Failed to use and restart external symbolizer!
    #0 0x5642643decc4 in blink::WebGLFramebuffer::RemoveAttachmentInternal(unsigned int, unsigned int)
        third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc:537:24
        (/tmp/chromium-asan-1654411/chrome+0x4273bcc4) (BuildId: 5c8f91628a04675e)
    #1 0x5642643dc1a7 in blink::WebGLFramebuffer::SetAttachmentInternal(unsigned int, unsigned int, unsigned int, blink::WebGLTexture*, int, int)
        third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc:505:3
        (/tmp/chromium-asan-1654411/chrome+0x427391a7) (BuildId: 5c8f91628a04675e)
    #2 0x5642643dbcd1 in blink::WebGLFramebuffer::SetAttachmentForBoundFramebuffer(unsigned int, unsigned int, unsigned int, blink::WebGLTexture*, int, int, int)
        third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc:0:0
        (/tmp/chromium-asan-1654411/chrome+0x42738cd1) (BuildId: 5c8f91628a04675e)
    #3 0x5642643d07a4 in blink::OVRMultiview2::framebufferTextureMultiviewOVR(unsigned int, unsigned int, blink::WebGLTexture*, int, int, int)
        third_party/blink/renderer/modules/webgl/ovr_multiview_2.cc:78:24
        (/tmp/chromium-asan-1654411/chrome+0x4272d7a4) (BuildId: 5c8f91628a04675e)
    #4 0x5642643d1489 in blink::(anonymous namespace)::v8_ovr_multiview_2::FramebufferTextureMultiviewOVROperationCallback(v8::FunctionCallbackInfo<v8::Value> const&)
        gen/third_party/blink/renderer/bindings/modules/v8/v8_ovr_multiview_2.cc:118:17
        (/tmp/chromium-asan-1654411/chrome+0x4272e489) (BuildId: 5c8f91628a04675e)
    #5 0x56423f354693 in Builtins_CallApiCallbackGeneric
        crtstuff.c:0:0
        (/tmp/chromium-asan-1654411/chrome+0x1d6b1693) (BuildId: 5c8f91628a04675e)
    #6 0x56423f352940 in Builtins_InterpreterEntryTrampoline
        crtstuff.c:0:0
        (/tmp/chromium-asan-1654411/chrome+0x1d6af940) (BuildId: 5c8f91628a04675e)
    #7 0x56423f34f6db in Builtins_JSEntryTrampoline
        crtstuff.c:0:0
        (/tmp/chromium-asan-1654411/chrome+0x1d6ac6db) (BuildId: 5c8f91628a04675e)
    #8 0x56423f34f42a in Builtins_JSEntry
        crtstuff.c:0:0
        (/tmp/chromium-asan-1654411/chrome+0x1d6ac42a) (BuildId: 5c8f91628a04675e)
    #9 0x56423a3358a9 in v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&)
        v8/src/execution/execution.cc:475:22
        (/tmp/chromium-asan-1654411/chrome+0x186928a9) (BuildId: 5c8f91628a04675e)
    #10 0x56423a3341d9 in v8::internal::Execution::Call(v8::internal::Isolate*, v8::internal::DirectHandle<v8::internal::Object>, v8::internal::DirectHandle<v8::internal::Object>, v8::base::Vector<v8::internal::DirectHandle<v8::internal::Object> const>)
        v8/src/execution/execution.cc:565:10
        (/tmp/chromium-asan-1654411/chrome+0x186911d9) (BuildId: 5c8f91628a04675e)
    #11 0x56423b076f7e in v8::internal::JSFinalizationRegistry::Cleanup(v8::internal::Isolate*, v8::internal::DirectHandle<v8::internal::JSFinalizationRegistry>)
        v8/src/objects/js-weak-refs.cc:77:9
        (/tmp/chromium-asan-1654411/chrome+0x193d3f7e) (BuildId: 5c8f91628a04675e)
    #12 0x564239f759b5 in v8::internal::InvokeFinalizationRegistryCleanupFromTask(v8::internal::DirectHandle<v8::internal::NativeContext>, v8::internal::DirectHandle<v8::internal::JSFinalizationRegistry>)
        v8/src/api/api.cc:12425:3
        (/tmp/chromium-asan-1654411/chrome+0x182d29b5) (BuildId: 5c8f91628a04675e)
    #13 0x56423a5ad5eb in v8::internal::FinalizationRegistryCleanupTask::RunInternal()
        v8/src/heap/finalization-registry-cleanup-task.cc:90:3
        (/tmp/chromium-asan-1654411/chrome+0x1890a5eb) (BuildId: 5c8f91628a04675e)
    #14 0x564255338aa0 in base::internal::Invoker<base::internal::FunctorTraits<void (v8::Task::*&&)(), std::__Cr::unique_ptr<v8::Task, std::__Cr::default_delete<v8::Task>>&&>, base::internal::BindState<true, true, false, void (v8::Task::*)(), std::__Cr::unique_ptr<v8::Task, std::__Cr::default_delete<v8::Task>>>, void ()>::RunOnce(base::internal::BindStateBase*)
        base/functional/bind_internal.h:740:12
        (/tmp/chromium-asan-1654411/chrome+0x33695aa0) (BuildId: 5c8f91628a04675e)
    #15 0x56424d3d0817 in base::TaskAnnotator::RunTaskImpl(base::PendingTask&)
        base/functional/callback.h:155:12
        (/tmp/chromium-asan-1654411/chrome+0x2b72d817) (BuildId: 5c8f91628a04675e)
    #16 0x56424d43f8b4 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(base::LazyNow*)
        base/task/common/task_annotator.h:112:5
        (/tmp/chromium-asan-1654411/chrome+0x2b79c8b4) (BuildId: 5c8f91628a04675e)
    #17 0x56424d43e645 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork()
        base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:345:40
        (/tmp/chromium-asan-1654411/chrome+0x2b79b645) (BuildId: 5c8f91628a04675e)
    #18 0x56424d290555 in base::MessagePumpDefault::Run(base::MessagePump::Delegate*)
        base/message_loop/message_pump_default.cc:66:55
        (/tmp/chromium-asan-1654411/chrome+0x2b5ed555) (BuildId: 5c8f91628a04675e)
    #19 0x56424d44104c in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, base::TimeDelta)
        base/task/sequence_manager/thread_controller_with_message_pump_impl.cc:660:12
        (/tmp/chromium-asan-1654411/chrome+0x2b79e04c) (BuildId: 5c8f91628a04675e)
    #20 0x56424d34dbb8 in base::RunLoop::Run(base::Location const&)
        base/run_loop.cc:135:14
        (/tmp/chromium-asan-1654411/chrome+0x2b6aabb8) (BuildId: 5c8f91628a04675e)
    #21 0x564259e8b7db in content::RendererMain(content::MainFunctionParams)
        content/renderer/renderer_main.cc:339:16
        (/tmp/chromium-asan-1654411/chrome+0x381e87db) (BuildId: 5c8f91628a04675e)
    #22 0x56424989df9f in content::RunZygote(content::ContentMainDelegate*)
        content/app/content_main_runner_impl.cc:666:14
        (/tmp/chromium-asan-1654411/chrome+0x27bfaf9f) (BuildId: 5c8f91628a04675e)
    #23 0x56424989f204 in content::RunOtherNamedProcessTypeMain(std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>> const&, content::MainFunctionParams, content::ContentMainDelegate*)
        content/app/content_main_runner_impl.cc:773:12
        (/tmp/chromium-asan-1654411/chrome+0x27bfc204) (BuildId: 5c8f91628a04675e)
    #24 0x5642498a20ed in content::ContentMainRunnerImpl::Run()
        content/app/content_main_runner_impl.cc:1165:10
        (/tmp/chromium-asan-1654411/chrome+0x27bff0ed) (BuildId: 5c8f91628a04675e)
    #25 0x56424989b9af in content::RunContentProcess(content::ContentMainParams, content::ContentMainRunner*)
        content/app/content_main.cc:356:36
        (/tmp/chromium-asan-1654411/chrome+0x27bf89af) (BuildId: 5c8f91628a04675e)
    #26 0x56424989bfac in content::ContentMain(content::ContentMainParams)
        content/app/content_main.cc:369:10
        (/tmp/chromium-asan-1654411/chrome+0x27bf8fac) (BuildId: 5c8f91628a04675e)
    #27 0x56423357c0bf in ChromeMain
        chrome/app/chrome_main.cc:221:12
        (/tmp/chromium-asan-1654411/chrome+0x118d90bf) (BuildId: 5c8f91628a04675e)
    #28 0x7fab070721c9 in __libc_start_call_main
        sysdeps/nptl/libc_start_call_main.h:58:16
        (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 328820b908de8ea1ef79afa8995e302e819163d7)
    #29 0x7fab0707228a in __libc_start_main
        csu/libc-start.c:360:3
        (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 328820b908de8ea1ef79afa8995e302e819163d7)
    #30 0x56423349e029 in _start
        ??:0:0
        (/tmp/chromium-asan-1654411/chrome+0x117fb029) (BuildId: 5c8f91628a04675e)

Address 0x7b9402009020 is a wild pointer inside of access range of size 0x000000000008.
SUMMARY: AddressSanitizer: use-after-poison in blink::WebGLFramebuffer::RemoveAttachmentInternal(unsigned int, unsigned int)
    third_party/blink/renderer/modules/webgl/webgl_framebuffer.cc:537:24
    (/tmp/chromium-asan-1654411/chrome+0x4273bcc4) (BuildId: 5c8f91628a04675e)
Shadow bytes around the buggy address:
  0x7b9402008d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b9402008e00: 00 00 00 00 00 00 f7 f7 f7 f7 f7 00 00 00 00 00
  0x7b9402008e80: 00 00 00 00 00 00 00 00 00 00 00 f7 f7 f7 00 00
  0x7b9402008f00: 00 00 00 f7 f7 f7 f7 f7 00 00 00 00 00 00 00 00
  0x7b9402008f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x7b9402009000: 00 00 00 00[f7]f7 f7 00 00 00 00 00 00 00 00 00
  0x7b9402009080: 00 00 00 00 00 00 00 00 f7 f7 f7 00 00 00 00 00
  0x7b9402009100: 00 00 00 00 00 00 00 00 00 00 00 00 f7 f7 f7 00
  0x7b9402009180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b9402009200: f7 f7 f7 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b9402009280: 00 00 00 00 f7 f7 f7 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb

NOTE: the stack trace above identifies the code that *accessed* the poisoned memory.
HINT: To identify the code that *poisoned* the memory, try the experimental setting ASAN_OPTIONS=poison_history_size=<size>.

==1==ADDITIONAL INFO

==1==Note: Please include this section with the ASan report.
Task trace:
    #0 0x56425532c44f in gin::V8ToBaseLocation(v8::SourceLocation const&)
        gin/converter.cc:289:10
        (/tmp/chromium-asan-1654411/chrome+0x3368944f) (BuildId: 5c8f91628a04675e)
    #1 0x5642606e621c in blink::DOMTimer::DOMTimer(blink::ExecutionContext&, blink::ScheduledAction*, base::TimeDelta, bool, blink::probe::AsyncTaskContext::ScanForAds)
        third_party/blink/renderer/core/scheduler/dom_timer.cc:348:27
        (/tmp/chromium-asan-1654411/chrome+0x3ea4321c) (BuildId: 5c8f91628a04675e)
    #2 0x5642606e621c in blink::DOMTimer::DOMTimer(blink::ExecutionContext&, blink::ScheduledAction*, base::TimeDelta, bool, blink::probe::AsyncTaskContext::ScanForAds)
        third_party/blink/renderer/core/scheduler/dom_timer.cc:348:27
        (/tmp/chromium-asan-1654411/chrome+0x3ea4321c) (BuildId: 5c8f91628a04675e)
    #3 0x5642512f7287 in IPC::ChannelAssociatedGroupController::Accept(mojo::Message*)
        ipc/ipc_mojo_bootstrap.cc:1138:13
        (/tmp/chromium-asan-1654411/chrome+0x2f654287) (BuildId: 5c8f91628a04675e)


Command line: `/proc/self/exe --type=renderer --gpu-client-id=6 --crashpad-handler-pid=2926502 --enable-crash-reporter=, --noerrdialogs --user-data-dir=/tmp/chromium-asan-151-profile-01 --change-stack-guard-on-fork=enable --disable-dev-shm-usage --file-url-path-alias=/gen=/tmp/chromium-asan-1654411/gen --remote-debugging-port=0 --ozone-platform=headless --lang=en-US --num-raster-threads=4 --enable-main-frame-before-activation --renderer-client-id=6 --time-ticks-at-unix-epoch=-1782698642359408 --gpu-channel-request-start-time-ticks=3269794668529 --launch-time-ticks=3269794675661 --shared-files=v8_context_snapshot_data:100 --field-trial-handle=3,i,1506818743404535082,4229230523870192825,262144 --disable-features=PaintHolding --variations-seed-version --pseudonymization-salt-handle=7,i,10557152309683851536,8784820902952286342,4 --trace-process-track-uuid=3190708991934122588`


==1==END OF ADDITIONAL INFO

==1==ABORTING

Disclaimer

This information is being shared by OpenAI solely for the purpose of improving security and reducing potential harm. This information is presented as-is. We make no representations or warranties, express or implied, as to the completeness, accuracy, or fitness for any particular purpose of the information. This includes, without limitation any suggestions or ideas presented on how to remedy or mitigate an identified vulnerability, including whether such suggestions or ideas would be effective and/or could have other negative impacts.

OpenAI disclaims any liability for direct or indirect damages arising from the reliance on, or use, misuse, or interpretation of this information. Any references to third-party systems, services, or entities are included solely for identification purposes and do not imply endorsement, responsibility, or attribution.

Reporting Credit

OpenAI Codex Security (amyb)

View on issue tracker