Medium chrome Logic Error 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient validation of untrusted input in Guest View
DescriptionInsufficient validation of untrusted input in Guest View
ComponentGuest View
Bug ClassLogic Error
Tracker516413817
Fix commitef9226cc3f6f (chromium/src) +15/-13
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-08

Changed Functions

FunctionChangeNotes
for
chrome/browser/glic/widget/glic_view.cc
modified

Files Changed

  • chrome/browser/glic/widget/glic_view.cc
  • chrome/browser/glic/widget/glic_view.h
  • components/guest_view/browser/guest_view_base.cc
From ef9226cc3f6f154dbf32ad2780f2cde7d363204a Mon Sep 17 00:00:00 2001
From: Zoraiz Naeem <[email protected]>
Date: Mon, 01 Jun 2026 13:07:45 -0700
Subject: [PATCH] Fix draggable region validation bypass in GuestViewBase

GuestViewBase::DraggableRegionsChanged was incorrectly substituting the
embedder's WebContents for the source WebContents when forwarding the
event to the embedder delegate. This laundering bypassed source
validation checks in downstream delegates like AppWindow.

This CL fixes the vulnerability by passing the original guest
WebContents to the embedder delegate.

Bug: b:516413817
Change-Id: I71d1c2bf75db0f7561df5214d9d97cf1d56610f2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7884657
Commit-Queue: Zoraiz Naeem <[email protected]>
Reviewed-by: James Cook <[email protected]>
Reviewed-by: Ian Wells <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1639613}
---

diff --git a/chrome/browser/glic/widget/glic_view.cc b/chrome/browser/glic/widget/glic_view.cc
index 7fe3ffdb..d4f7d1d 100644
--- a/chrome/browser/glic/widget/glic_view.cc
+++ b/chrome/browser/glic/widget/glic_view.cc
@@ -101,10 +101,6 @@
 void GlicView::DraggableRegionsChanged(
     const std::vector<blink::mojom::DraggableRegionPtr>& regions,
     content::WebContents* contents) {
-  // `GlicView::DraggableRegionsChanged()` is called when draggable regions for
-  // either the main-webcontents or guest-webcontents are changed.
-  // guest-webcontents are the webcontents associated to `<webview>` hosting the
-  // glic web app,
   SkRegion sk_region;
   for (const auto& region : regions) {
     sk_region.op(
@@ -113,11 +109,18 @@
         region->draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op);
   }
 
-  SetDraggableRegion(sk_region);
+  // `GlicView::DraggableRegionsChanged()` is called when draggable regions for
+  // either the main-webcontents or guest-webcontents are changed.
+  // guest-webcontents are the webcontents associated to `<webview>` hosting the
+  // glic web app,
+  const bool is_webview_contents = web_contents() != contents;
+  SetDraggableRegion(sk_region, /*for_webview=*/is_webview_contents);
 }
 
 bool GlicView::IsPointWithinDraggableRegion(const gfx::Point& point) {
-  return draggable_region_.contains(point.x(), point.y());
+  // Draggable region of webview takes precedence.
+  return webview_draggable_region_.contains(point.x(), point.y()) ||
+         draggable_region_.contains(point.x(), point.y());
 }
 
 void GlicView::UpdateBackgroundColor() {
@@ -162,10 +165,8 @@
   return false;
 }
 
-void GlicView::SetDraggableRegion(const SkRegion& region) {
-  // Since <webview> covers the entire main web-contents, overriding the
-  // draggable regions set by main web-contents (if any) is okay.
-  draggable_region_ = region;
+void GlicView::SetDraggableRegion(const SkRegion& region, bool for_webview) {
+  (for_webview ? webview_draggable_region_ : draggable_region_) = region;
 }
 
 std::optional<SkColor> GlicView::GetClientBackgroundColor() {
diff --git a/chrome/browser/glic/widget/glic_view.h b/chrome/browser/glic/widget/glic_view.h
index 28970d5b..0febaa3 100644
--- a/chrome/browser/glic/widget/glic_view.h
+++ b/chrome/browser/glic/widget/glic_view.h
@@ -76,7 +76,7 @@
   }
 
  private:
-  void SetDraggableRegion(const SkRegion& region);
+  void SetDraggableRegion(const SkRegion& region, bool for_webview);
 
   std::optional<SkColor> GetClientBackgroundColor();
 
@@ -86,6 +86,7 @@
 
   // Defines the region of the view from which it can be dragged.
   SkRegion draggable_region_;
+  SkRegion webview_draggable_region_;
 
   views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
   base::WeakPtrFactory<GlicView> weak_ptr_factory_{this};
diff --git a/components/guest_view/browser/guest_view_base.cc b/components/guest_view/browser/guest_view_base.cc
index 71c002e..8ed6b08d 100644
--- a/components/guest_view/browser/guest_view_base.cc
+++ b/components/guest_view/browser/guest_view_base.cc
@@ -1042,8 +1042,8 @@
     return;
   }
 
-  embedder_web_contents()->GetDelegate()->DraggableRegionsChanged(
-      regions, embedder_web_contents());
+  embedder_web_contents()->GetDelegate()->DraggableRegionsChanged(regions,
+                                                                  contents);
 }
 
 void GuestViewBase::OnZoomControllerDestroyed(zoom::ZoomController* source) {
Loading diff…

Original Bug Report

reported by [email protected]

Draggable region validation bypass in GuestViewBase allowing clickjacking

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 security bypass exists in GuestViewBase where forwarding draggable regions from a guest to the embedder delegate substitutes the embedder’s WebContents as the source parameter. This l laundering bypasses critical source-validation checks in AppWindow and AppBrowserController delegates. Consequently, an untrusted guest frame can potentially define arbitrary draggable regions over the entire native window of the host application, enabling clickjacking and interaction suppression.

Affected files:

  • components/guest_view/browser/guest_view_base.cc
  • extensions/browser/app_window/app_window.cc
  • chrome/browser/ui/web_applications/app_browser_controller.cc

Estimated timestamp from git blame: 2025-12-29

Root Cause Analysis

In components/guest_view/browser/guest_view_base.cc, when a guest webpage notifies the browser of a change in its draggable regions, GuestViewBase::DraggableRegionsChanged gets called:

void GuestViewBase::DraggableRegionsChanged(
    const std::vector<blink::mojom::DraggableRegionPtr>& regions,
    content::WebContents* contents) {
  CHECK(!base::FeatureList::IsEnabled(features::kGuestViewMPArch));

  if (!attached() || !embedder_web_contents()->GetDelegate()) {
    return;
  }

  embedder_web_contents()->GetDelegate()->DraggableRegionsChanged(
      regions, embedder_web_contents()); // <-- Source substituted to embedder_web_contents()
}

Instead of forwarding the actual guest WebContents* source (contents), it substitutes the embedder_web_contents() pointer.

This substitution (or laundering) bypasses critical verification checks performed by the embedder delegates:

  1. AppWindow::DraggableRegionsChanged (extensions/browser/app_window/app_window.cc):

    void AppWindow::DraggableRegionsChanged(
        const std::vector<blink::mojom::DraggableRegionPtr>& regions,
        content::WebContents* contents) {
      CHECK_EQ(contents, web_contents())
          << "Received DraggableRegionsChanged() notification for unexpected web contents";
      native_app_window_->DraggableRegionsChanged(regions);
    }
    

    The CHECK_EQ is bypassed because contents is substituted with the embedder’s web_contents() (which matches web_contents()).

  2. AppBrowserController::DraggableRegionsChanged (chrome/browser/ui/web_applications/app_browser_controller.cc):

    void AppBrowserController::DraggableRegionsChanged(
        const std::vector<blink::mojom::DraggableRegionPtr>& regions,
        content::WebContents* contents) {
      content::WebContents* active_contents = 
          browser()->tab_strip_model()->GetActiveWebContents();
      if (contents != active_contents) {
        return;
      }
      ...
    

    The active WebContents verification check is bypassed because contents has been substituted with the active embedder WebContents.

Potential Attack Vector & Impact

Because coordinate translation is not applied to the forwarded vector, these regions are interpreted relative to the native coordinates of the outer/embedder window.

Furthermore, since draggable regions are standard CSS features (-webkit-app-region: drag), an untrusted webpage loaded inside a <webview> (in a Chrome App) or <controlledframe> (in an Isolated Web App) can trigger this notification natively without requiring a compromised renderer.

By specifying arbitrary coordinates (e.g., covering the entire native window frame or targeting specific coordinates of host controls), the guest page can mark arbitrary regions of the host UI as draggable. Any clicks in these areas will be captured by the OS window manager as window dragging gestures, which suppresses normal mouse click events from being processed by the application’s trusted elements. This enables clickjacking or UI redressing attacks where the attacker can selectively allow clicks only on specific elements (like a “Yes” or “Allow” button) while making “No” or “Deny” buttons unclickable.

Suggested Steps to Reproduce (Potential)

Please note: These are suggested/potential steps to reproduce. Our tooling agent doesn’t yet have the ability to run code or dynamically verify the exploit.

  1. Install an Isolated Web App (IWA) containing a <controlledframe src="https://attacker.example"> or a frameless Chrome App containing <webview src="https://attacker.example">.
  2. On the attacker-controlled guest webpage https://attacker.example, use the standard CSS property -webkit-app-region: drag; on the page body, or dynamically change the region style.
  3. The layout engine will compile the regions and transmit them to the browser via the LocalMainFrameHost::DraggableRegionsChanged Mojo IPC.
  4. Observe that the check in AppWindow::DraggableRegionsChanged or AppBrowserController::DraggableRegionsChanged passes successfully because the source was laundered to embedder_web_contents().
  5. Click on the host application’s trusted UI elements (outside the boundaries of the guest iframe) and observe that clicks are intercepted and treated as window-dragging gestures by the OS.

Suggested Fix

To resolve this issue, GuestViewBase::DraggableRegionsChanged must not substitute the source WebContents parameter with the embedder’s WebContents. Instead, the original guest WebContents parameter should be passed (or the delegate should be updated to handle guest-origin region updates appropriately, such as translating coordinates relative to the guest’s position in the embedder window or explicitly discarding guest draggable region requests if the embedder does not want to support them).

Evaluated with Chrome root at commit: a2bea94528f4bd6cc57739c43fa3bb890b8367d3


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