Low watch CVSS 4.3 chrome Authorization Error 🔧 Commit mapped

Overview

Low
Severity
4.3
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncorrect authorization in Controls
DescriptionIncorrect authorization in Controls
ComponentControls
Bug ClassAuthorization Error
Action tierwatch — logic/policy bug — security-relevant, no memory-unsafety
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.
Tracker514408247
Fix commit70b3b177f7d9 (chromium/src) +40/-4
CWECWE-863
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-05-18 (per vendor advisory)
Fix landed2026-07-15 (public git)
Disclosed2026-08-25
Patch gap41 days — fix public in source before the advisory

Background

`isTrusted`
A DOM event flag that is true only for events dispatched by the user agent (genuine hardware/UA-generated events) and false for events synthesized by script via dispatchEvent.
`MediaControlsRotateToFullscreenDelegate`
A Blink media-controls delegate that watches screen orientationchange events and, when the device rotates to match a playing video’s orientation, transitions the video into fullscreen.
Transient user activation
A short-lived “user gesture” state required to authorize privileged actions such as entering fullscreen, normally granted only by genuine user interaction.
`Invoke` / `OnScreenOrientationChange`
Invoke is the delegate’s event handler dispatch; OnScreenOrientationChange performs the orientation-driven fullscreen transition.

Root Cause Analysis

In media_controls_rotate_to_fullscreen_delegate.cc, the kOrientationchange branch of MediaControlsRotateToFullscreenDelegate::Invoke unconditionally called OnScreenOrientationChange() for any event of type orientationchange, without checking whether the event was genuine. Because script can dispatch a synthetic orientationchange event (isTrusted == false) at the window, page JavaScript could drive the rotate-to-fullscreen logic as though the hardware had rotated. The invariant violated is that only genuine, user-agent-generated orientation changes should be able to grant transient user activation and trigger a fullscreen transition.

The fix wraps the OnScreenOrientationChange() call in an if (event->isTrusted()) guard, so untrusted synthetic events are ignored and fall through to the return. This tightens the check: trusted events behave exactly as before, while script-forged events no longer reach the fullscreen path.

Key insight
The core mistake was treating any orientationchange event as a real rotation without verifying isTrusted, letting scripted events forge a user-activation-bearing fullscreen trigger; the fix gates OnScreenOrientationChange() on event->isTrusted().

Attack Path

  1. Set up matching video/screen orientation An attacker page plays a video (e.g. a landscape video on a portrait screen) so the rotate-to-fullscreen condition would be satisfied by a rotation.
  2. Forge an orientation change Page script dispatches a synthetic orientationchange event at the window (isTrusted == false), optionally after adjusting reported screen orientation, without any real device rotation or user gesture.
  3. Handler runs the fullscreen path Pre-patch, MediaControlsRotateToFullscreenDelegate::Invoke reached OnScreenOrientationChange() for the untrusted event, treating it as a genuine rotation.
  4. Fullscreen entry / activation granted The delegate transitions the video into fullscreen and, per the commit message, this path can grant transient user activation—both without user intent; the untrusted event is now rejected by the isTrusted() guard.

Impact Assessment

A malicious web page could enter fullscreen (and, per the advisory/commit, obtain transient user activation) without genuine user interaction by dispatching a forged orientationchange event, running in the renderer’s page context. The advisory classifies this as an AuthorizationError / “Incorrect authorization in Controls” and requires a playing video meeting the rotate-to-fullscreen orientation condition; it does not state exploitation in the wild. Any further abuse of the improperly granted transient user activation (e.g. gating other gesture-restricted APIs) is (inferred) beyond what the patch demonstrates.

Changed Functions

FunctionChangeNotes
if
third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
modified
TEST_F
third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
modified

Files Changed

  • third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc
  • third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc

Audit Directions

  • Missing `isTrusted` on gesture/privilege triggers
    Search other event handlers that grant transient user activation or perform fullscreen, pointer-lock, or similar gated transitions for branches that act on an event type without checking event->isTrusted().
  • Synthetic-event-reachable delegates
    Audit media-controls and other UA-facing delegates whose Invoke/handler methods are dispatched for event types a page can also dispatch via dispatchEvent.
  • UA-only signals treated as authoritative
    Review code that infers physical/device state (orientation, sensors, input) from DOM events and confirm it distinguishes trusted UA events from script-forged ones.
From 70b3b177f7d9116a2c181a204b9f37256fe997de Mon Sep 17 00:00:00 2001
From: Frank Liberato <liberato@chromium.org>
Date: Wed, 15 Jul 2026 10:47:58 -0700
Subject: [PATCH] Verify isTrusted for orientationchange in MediaControlsRotateToFullscreenDelegate

This CL adds an isTrusted check to the kOrientationchange event handler in MediaControlsRotateToFullscreenDelegate::Invoke, ensuring that only genuine hardware-triggered orientation changes can grant transient user activation and trigger fullscreen transitions.

Added a unit test to verify that untrusted orientationchange events are ignored.

BUG=514408247

TAG=agy

CONV=ca3e205f-82aa-4e9b-9ec6-0b80c1443cbb

Change-Id: Ibe1fde6b37867bcc6249dae5aece7ce923bc61d6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8092753
Reviewed-by: Tommy Steimel <steimel@chromium.org>
Auto-Submit: Frank Liberato <liberato@chromium.org>
Commit-Queue: Benjamin Keen <bkeen@google.com>
Reviewed-by: Benjamin Keen <bkeen@google.com>
Cr-Commit-Position: refs/heads/main@{#1662734}
---
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc
index 1667b39..c8bfa1a 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate.cc
@@ -112,7 +112,9 @@
     return;
   }
   if (event->type() == event_type_names::kOrientationchange) {
-    OnScreenOrientationChange();
+    if (event->isTrusted()) {
+      OnScreenOrientationChange();
+    }
     return;
   }
 
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
index 538c8783..7ea0588 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
@@ -27,6 +27,7 @@
 #include "third_party/blink/renderer/modules/device_orientation/device_orientation_data.h"
 #include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
 #include "third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
@@ -155,8 +156,15 @@
     GetVideo().removeAttribute(html_names::kControlsAttr);
   }
 
-  void DispatchEvent(EventTarget& target, const AtomicString& type) {
-    target.DispatchEvent(*Event::Create(type));
+  void DispatchEvent(EventTarget& target,
+                     const AtomicString& type,
+                     bool is_trusted = false) {
+    Event* event = Event::Create(type);
+    if (is_trusted) {
+      target.DispatchEvent(*event);
+    } else {
+      target.dispatchEventForBindings(event, IGNORE_EXCEPTION);
+    }
   }
 
   void InitScreenAndVideo(
@@ -231,7 +239,8 @@
 void MediaControlsRotateToFullscreenDelegateTest::RotateTo(
     display::mojom::blink::ScreenOrientation new_screen_orientation) {
   GetChromeClient().MockScreenInfo().orientation_type = new_screen_orientation;
-  DispatchEvent(GetWindow(), event_type_names::kOrientationchange);
+  DispatchEvent(GetWindow(), event_type_names::kOrientationchange,
+                true /* is_trusted */);
   test::RunPendingTasks();
 }
 
@@ -803,4 +812,29 @@
   EXPECT_TRUE(GetVideo().IsFullscreen());
 }
 
+TEST_F(MediaControlsRotateToFullscreenDelegateTest, UntrustedEventIgnored) {
+  // Portrait screen, landscape video.
+  InitScreenAndVideo(display::mojom::blink::ScreenOrientation::kPortraitPrimary,
+                     gfx::Size(640, 480));
+  EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation());
+  EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation());
+
+  // Play video.
+  PlayVideo();
+  UpdateVisibilityObserver();
+
+  EXPECT_TRUE(ObservedVisibility());
+  EXPECT_FALSE(GetVideo().IsFullscreen());
+
+  // Simulate rotation in ScreenInfo but dispatch an UNTRUSTED event.
+  GetChromeClient().MockScreenInfo().orientation_type =
+      display::mojom::blink::ScreenOrientation::kLandscapePrimary;
+  DispatchEvent(GetWindow(), event_type_names::kOrientationchange,
+                false /* is_trusted */);
+  test::RunPendingTasks();
+
+  // Should NOT enter fullscreen because the event was untrusted.
+  EXPECT_FALSE(GetVideo().IsFullscreen());
+}
+
 }  // namespace blink
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
index 538c8783..7ea0588 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_rotate_to_fullscreen_delegate_test.cc
@@ -27,6 +27,7 @@
 #include "third_party/blink/renderer/modules/device_orientation/device_orientation_data.h"
 #include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
 #include "third_party/blink/renderer/modules/screen_orientation/screen_orientation_controller.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
@@ -155,8 +156,15 @@
     GetVideo().removeAttribute(html_names::kControlsAttr);
   }
 
-  void DispatchEvent(EventTarget& target, const AtomicString& type) {
-    target.DispatchEvent(*Event::Create(type));
+  void DispatchEvent(EventTarget& target,
+                     const AtomicString& type,
+                     bool is_trusted = false) {
+    Event* event = Event::Create(type);
+    if (is_trusted) {
+      target.DispatchEvent(*event);
+    } else {
+      target.dispatchEventForBindings(event, IGNORE_EXCEPTION);
+    }
   }
 
   void InitScreenAndVideo(
@@ -231,7 +239,8 @@
 void MediaControlsRotateToFullscreenDelegateTest::RotateTo(
     display::mojom::blink::ScreenOrientation new_screen_orientation) {
   GetChromeClient().MockScreenInfo().orientation_type = new_screen_orientation;
-  DispatchEvent(GetWindow(), event_type_names::kOrientationchange);
+  DispatchEvent(GetWindow(), event_type_names::kOrientationchange,
+                true /* is_trusted */);
   test::RunPendingTasks();
 }
 
@@ -803,4 +812,29 @@
   EXPECT_TRUE(GetVideo().IsFullscreen());
 }
 
+TEST_F(MediaControlsRotateToFullscreenDelegateTest, UntrustedEventIgnored) {
+  // Portrait screen, landscape video.
+  InitScreenAndVideo(display::mojom::blink::ScreenOrientation::kPortraitPrimary,
+                     gfx::Size(640, 480));
+  EXPECT_EQ(SimpleOrientation::kPortrait, ObservedScreenOrientation());
+  EXPECT_EQ(SimpleOrientation::kLandscape, ComputeVideoOrientation());
+
+  // Play video.
+  PlayVideo();
+  UpdateVisibilityObserver();
+
+  EXPECT_TRUE(ObservedVisibility());
+  EXPECT_FALSE(GetVideo().IsFullscreen());
+
+  // Simulate rotation in ScreenInfo but dispatch an UNTRUSTED event.
+  GetChromeClient().MockScreenInfo().orientation_type =
+      display::mojom::blink::ScreenOrientation::kLandscapePrimary;
+  DispatchEvent(GetWindow(), event_type_names::kOrientationchange,
+                false /* is_trusted */);
+  test::RunPendingTasks();
+
+  // Should NOT enter fullscreen because the event was untrusted.
+  EXPECT_FALSE(GetVideo().IsFullscreen());
+}
+
 }  // namespace blink
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.