Overview

Critical
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Views
DescriptionUse after free in Views
ComponentViews
Bug ClassUAF
Tracker519262990
Fix commitd8c59a2fbbbc (chromium/src) +4/-0
CISA KEVNot listed
CreditedGoogle
Disclosed2026-07-29

Changed Functions

FunctionChangeNotes
if
chrome/browser/ui/views/frame/browser_view.cc
modified

Files Changed

  • chrome/browser/ui/views/frame/browser_view.cc
From d8c59a2fbbbca18fafb7cc19f2d60682ef348d27 Mon Sep 17 00:00:00 2001
From: Muyao Xu <[email protected]>
Date: Tue, 02 Jun 2026 17:48:59 -0700
Subject: [PATCH] [Fullscreen] Fix potential UAF in BrowserView::SetBounds

When exiting fullscreen, synchronous window destruction can occur on the
UI thread, deleting the BrowserView object and resulting in a UAF issue.

Bug: 519262990
Change-Id: I2eb6187f82d316c03c0d9aeeb60eac015d7c7a2d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7897839
Reviewed-by: Mike Wasserman <[email protected]>
Commit-Queue: Mike Wasserman <[email protected]>
Auto-Submit: Muyao Xu <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1640600}
---

diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index c5b196b2..9a792d72 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -1593,7 +1593,11 @@
     return;
   }
 
+  auto weak_ptr = weak_ptr_factory_.GetWeakPtr();
   exclusive_access_context_->ExitFullscreen();
+  if (!weak_ptr) {
+    return;
+  }
 
   // If the BrowserFrameView has been created, give it a chance to handle the
   // BrowserWidget's bounds change.
Loading diff…

Original Bug Report

reported by [email protected]

Potential Browser-Process Use-After-Free in BrowserView::SetBounds during ExitFullscreen

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 Use-After-Free (UAF) vulnerability exists in BrowserView::SetBounds due to the lack of a liveness guard after exiting fullscreen. When exiting fullscreen, synchronous widget destruction can occur on the UI thread during nested event loops or message dispatches. Subsequent dereferencing of members on the deleted BrowserView can lead to a browser-process crash or potential arbitrary code execution.

Affected files:

  • chrome/browser/ui/views/frame/browser_view.cc

Estimated timestamp from git blame: 2024-07-18

Root Cause Analysis

In chrome/browser/ui/views/frame/browser_view.cc:1591-1605, the function BrowserView::SetBounds is implemented as follows:

void BrowserView::SetBounds(const gfx::Rect& bounds) {
  if (BrowserWindowFullscreenController::From(browser())->IsForceFullscreen())
    return;

  exclusive_access_context_->ExitFullscreen();
  
  if (auto* const frame_view = GetFrameView()) {
    frame_view->SetFrameBounds(bounds);
  } else {
    browser_widget_->SetBounds(bounds);
  }
}

The call to exclusive_access_context_->ExitFullscreen() triggers a synchronous fullscreen exit transition. Depending on the target platform:

  • macOS: -[NSWindow toggleFullScreen:] is executed inside the Remote Cocoa app shim layer. AppKit spins a nested event-tracking run loop to perform the fullscreen transition animation.
  • Windows: FullscreenHandler::SetFullscreen triggers a synchronous Win32 ::SetWindowPos(hwnd, ..., SWP_FRAMECHANGED) call, which synchronously dispatches window messages.

If a deferred window close request (such as a queued window.close() or posted close task) is processed during this nested run loop or synchronous message dispatch, the BrowserWidget and its associated view hierarchy (including the BrowserView itself) can be synchronously destroyed.

Because BrowserView::SetBounds does not employ a base::WeakPtr or liveness guard after the ExitFullscreen() call, control returns to a dangling this context. The subsequent call to GetFrameView() reads the browser_widget_ unique pointer from the freed BrowserView allocation, leading to a Use-After-Free (UAF). If the deallocated memory is reclaimed by an attacker, the virtual call frame_view->SetFrameBounds(bounds) could be hijacked to achieve arbitrary code execution in the context of the unsandboxed browser process.

Suggested/Potential Trigger Path

Since our tooling agent currently lacks the capability to execute and validate interactive proof-of-concept code, this is a potential trigger path based on static code analysis:

  1. A compromised renderer opens a same-origin popup window (where !is_type_normal() is true).
  2. The popup is placed into browser fullscreen (e.g., via F11 or macOS green button), resulting in a fullscreen state mode of FullscreenMode::kWindowed.
  3. The popup’s renderer queues a window close request (e.g., window.close()).
  4. Immediately following this, the renderer issues a blink::mojom::LocalMainFrameHost::SetWindowRect Mojo call.
  5. In the browser process, ForSecurityDropFullscreen is bypassed because the window is in browser fullscreen (kWindowed), allowing the bounds update to proceed.
  6. Browser::SetContentsBounds forwards the request to BrowserView::SetBounds.
  7. BrowserView::SetBounds calls ExitFullscreen(), entering the synchronous platform-specific transition (nested run loop on macOS / synchronous dispatch on Windows).
  8. The queued close request executes during this nested event processing, synchronously deleting the BrowserWidget and the BrowserView.
  9. The transition finishes, control returns to BrowserView::SetBounds, and the subsequent call to GetFrameView() triggers the UAF.

Suggested Fix

The vulnerability can be mitigated by introducing a base::WeakPtr liveness check immediately following the ExitFullscreen() call:

void BrowserView::SetBounds(const gfx::Rect& bounds) {
  if (BrowserWindowFullscreenController::From(browser())->IsForceFullscreen())
    return;

  auto weak_ptr = weak_ptr_factory_.GetWeakPtr();
  exclusive_access_context_->ExitFullscreen();
  if (!weak_ptr) {
    return;
  }

  if (auto* const frame_view = GetFrameView()) {
    frame_view->SetFrameBounds(bounds);
  } else {
    browser_widget_->SetBounds(bounds);
  }
}

Evaluated with Chrome root at commit: 87214e6721f6c34afd9181b80769a24c0c601c50


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