CVE-2026-7917
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifcontent/browser/renderer_host/render_frame_host_impl.cc |
modified | |
ifcontent/browser/web_contents/web_contents_impl.cc |
modified |
Files Changed
content/browser/renderer_host/render_frame_host_impl.cccontent/browser/web_contents/web_contents_impl.cc
Patch
From 91d5baaef742d5b9e081914e2a373f3a79a60b41 Mon Sep 17 00:00:00 2001
From: Arthur Sonzogni <arthursonzogni@chromium.org>
Date: Thu, 02 Apr 2026 18:28:34 -0700
Subject: [PATCH] [Fullscreen] Guard against UAF during EnterFullscreenMode
Entering fullscreen on Windows can spin a nested message loop via
::SetWindowPos, allowing a pending task to destroy the tab. This adds
WeakPtr guards to prevent UAF upon return, matching the existing fix
for ExitFullscreenMode (crbug.com/1506535).
I haven't added tests because testing the precise timing of this
synchronous Windows-specific destruction is difficult to get right,
especially from a Linux workstation.
Fixed: 498752242
Change-Id: I90c926214e9548208de1dbe54c0201a5393a512d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7722343
Commit-Queue: Rakina Zata Amni <rakina@chromium.org>
Reviewed-by: Rakina Zata Amni <rakina@chromium.org>
Auto-Submit: Arthur Sonzogni <arthursonzogni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1609608}
---
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 9c95b15..ac474e22 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -9264,7 +9264,13 @@
if (had_fullscreen_token && !GetView()->HasFocus()) {
GetView()->Focus();
}
+ // This may spin the message loop and destroy this object.
+ // See crbug.com/1506535, crbug.com/498752242.
+ base::WeakPtr<RenderFrameHostImpl> weak_ptr = GetWeakPtr();
delegate_->EnterFullscreenMode(this, *options);
+ if (!weak_ptr) {
+ return;
+ }
delegate_->FullscreenStateChanged(this, /*is_fullscreen=*/true,
std::move(options));
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index b0f2bd329..3e0c8bd 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4806,7 +4806,13 @@
}
if (delegate_) {
+ // This may spin the message loop and destroy this object.
+ // See crbug.com/1506535, crbug.com/498752242.
+ base::WeakPtr<WebContents> weak_ptr = GetWeakPtr();
delegate_->EnterFullscreenModeForTab(requesting_frame, options);
+ if (!weak_ptr) {
+ return;
+ }
if (keyboard_lock_widget_) {
delegate_->RequestKeyboardLock(this, esc_key_locked_);
@@ -4834,8 +4840,9 @@
base::TimeTicks::Now());
if (delegate_) {
- // This may spin the message loop and destroy this object crbug.com/1506535
- base::WeakPtr<WebContentsImpl> weak_ptr = weak_factory_.GetWeakPtr();
+ // This may spin the message loop and destroy this object.
+ // See crbug.com/1506535, crbug.com/498752242.
+ base::WeakPtr<WebContents> weak_ptr = GetWeakPtr();
delegate_->ExitFullscreenModeForTab(this);
if (!weak_ptr) {
return;
Original Bug Report
Browser Process UAF in WebContentsImpl::EnterFullscreenMode
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 without the security team.
Overview: A potential Use-After-Free (UAF) vulnerability exists in the browser process on Windows when a renderer requests fullscreen mode. The transition synchronously calls a Win32 API that can spin a nested message loop, allowing pending tab-destruction tasks to execute and free the WebContents and RenderFrameHost. Upon returning from the nested loop, the code unsafely dereferences these destroyed objects, potentially leading to sandbox escape and Remote Code Execution.
Affected files:
content/browser/web_contents/web_contents_impl.cccontent/browser/renderer_host/render_frame_host_impl.cc
Estimated timestamp from git blame: 2024-07-17
Summary
A Use-After-Free (UAF) vulnerability exists in the browser process when entering fullscreen mode on Windows. The issue arises because the fullscreen entry path lacks the WeakPtr guards that were previously implemented for the corresponding fullscreen exit path (see crbug.com/1506535).
Technical Details
When a renderer requests fullscreen, the browser-side call stack reaches RenderFrameHostImpl::EnterFullscreen and WebContentsImpl::EnterFullscreenMode. On Windows, this execution path eventually routes to ui/views/win/fullscreen_handler.cc, which performs a synchronous window message dispatch via ::SetWindowPos with SWP_FRAMECHANGED.
As explicitly documented in Chromium’s UI code (e.g., ui/views/win/hwnd_message_handler.cc), the ::SetWindowPos API can spin a nested message loop to process synchronous window messages. This allows pending tasks in the UI thread’s message pump—such as an IPC command to destroy the tab—to execute immediately.
If the WebContentsImpl or RenderFrameHostImpl is cleanly destroyed during this nested loop, the raw_ptr reference counts in standard holding structures will drop to zero, fully releasing the memory to the allocator (circumventing MiraclePtr/BackupRefPtr protections). However, the implicit this pointers on the executing C++ stack remain as raw, un-instrumented pointers.
When the stack unwinds back to the calling methods, the code continues to dereference this:
WebContentsImpl::EnterFullscreenMode: After callingdelegate_->EnterFullscreenModeForTab(...), the code accesseskeyboard_lock_widget_, performs a virtual call ondelegate_->RequestKeyboardLock, and accessesobservers_.RenderFrameHostImpl::EnterFullscreen: After theWebContentsreturns, this method performs a virtual call ondelegate_->FullscreenStateChanged(...).
An attacker who reallocates the freed memory (heap spraying) can control these delegate_ and observers_ pointers, hijacking virtual method calls to achieve Remote Code Execution (RCE) in the unsandboxed browser process.
Potential Reproduction Steps
Note: These are suggested steps based on static analysis by an AI agent; a functional Proof of Concept has not yet been executed to confirm exploitability.
- Compromise a Renderer: Gain initial code execution in a renderer process.
- Transient Activation: Wait for a legitimate user interaction (e.g., a click) to satisfy the transient activation requirement for entering fullscreen.
- Queue Tab Destruction: Execute an IPC or DOM operation (like
window.close()or cross-process frame navigation) that queues an asynchronous tab destruction task on the browser’s UI thread. - Request Fullscreen: Synchronously send the Mojo IPC
LocalFrameHost.EnterFullscreen(options). - Nested Loop Triggered: The browser process enters
WebContentsImpl::EnterFullscreenModeand ultimately calls the Win32::SetWindowPosAPI, spinning a nested message loop. - Object Destruction: The queued tab destruction task executes within the nested loop, cleanly destroying the
WebContentsandRenderFrameHostobjects. - Heap Spray: The compromised renderer sprays the browser heap via IPC to reclaim the exact memory region of the freed objects with a forged vtable structure.
- UAF and RCE: The Win32 API returns, the stack unwinds, and the browser process dereferences the attacker-controlled memory (e.g.,
delegate_->RequestKeyboardLock), hijacking the instruction pointer.
Suggested Fix
Implement the same protection used in WebContentsImpl::ExitFullscreenMode (fixed in crbug.com/1506535).
In WebContentsImpl::EnterFullscreenMode, capture a WeakPtr before calling the delegate, and check its validity before proceeding:
if (delegate_) {
base::WeakPtr<WebContentsImpl> weak_ptr = weak_factory_.GetWeakPtr();
delegate_->EnterFullscreenModeForTab(requesting_frame, options);
if (!weak_ptr) {
return;
}
if (keyboard_lock_widget_) {
delegate_->RequestKeyboardLock(this, esc_key_locked_);
}
}
A similar WeakPtr check should be applied in RenderFrameHostImpl::EnterFullscreen around the delegate_->EnterFullscreenMode(this, *options); call to prevent the subsequent delegate_->FullscreenStateChanged(...) call on a destroyed frame.
Evaluated with Chrome root at commit: ff3d2b74fa39431785bd60e51463b08fcc71ee33
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.