Chrome · PermissionElement
CVE-2026-79098
Logic Error in PermissionElement
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifthird_party/blink/renderer/core/html/html_capability_element_base.cc |
modified | |
TEST_Fthird_party/blink/renderer/core/html/html_capability_element_base_test.cc |
modified |
Files Changed
third_party/blink/renderer/core/html/html_capability_element_base.ccthird_party/blink/renderer/core/html/html_capability_element_base.hthird_party/blink/renderer/core/html/html_capability_element_base_test.cc
Patch
From 3a9b444e1f27bbf25c28289f93de51e443678f5a Mon Sep 17 00:00:00 2001 From: Stefan Zager <[email protected]> Date: Fri, 10 Jul 2026 12:49:50 -0700 Subject: [PATCH] [IOv2] Delete visibility observer when pepc element removed from DOM Bug: 514010111 Change-Id: I6b5f58b149505ed315bb91bbd5c4de9110967971 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8067916 Reviewed-by: Philip Rogers <[email protected]> Commit-Queue: Stefan Zager <[email protected]> Cr-Commit-Position: refs/heads/main@{#1660470} --- diff --git a/third_party/blink/renderer/core/html/html_capability_element_base.cc b/third_party/blink/renderer/core/html/html_capability_element_base.cc index ba61a89..69460a67c 100644 --- a/third_party/blink/renderer/core/html/html_capability_element_base.cc +++ b/third_party/blink/renderer/core/html/html_capability_element_base.cc @@ -360,6 +360,10 @@ if (auto* view = GetDocument().View()) { view->UnregisterFromLifecycleNotifications(this); } + if (!performing_reattach && intersection_observer_) { + intersection_observer_->disconnect(); + intersection_observer_ = nullptr; + } } void HTMLCapabilityElementBase::RemovedFrom(ContainerNode& insertion_point) { diff --git a/third_party/blink/renderer/core/html/html_capability_element_base.h b/third_party/blink/renderer/core/html/html_capability_element_base.h index 5e01e30..0c71c7f 100644 --- a/third_party/blink/renderer/core/html/html_capability_element_base.h +++ b/third_party/blink/renderer/core/html/html_capability_element_base.h @@ -211,6 +211,8 @@ FRIEND_TEST_ALL_PREFIXES(HTMLCapabilityElementBaseIntersectionTest, IntersectionChanged); FRIEND_TEST_ALL_PREFIXES(HTMLCapabilityElementBaseIntersectionTest, + MovePEPCFromIframeAndDestroyIframe); + FRIEND_TEST_ALL_PREFIXES(HTMLCapabilityElementBaseIntersectionTest, IntersectionChangedDisableEnableDisable); FRIEND_TEST_ALL_PREFIXES(HTMLCapabilityElementBaseIntersectionTest, ContainerDivRotates); diff --git a/third_party/blink/renderer/core/html/html_capability_element_base_test.cc b/third_party/blink/renderer/core/html/html_capability_element_base_test.cc index 2886eaf8..bcaca0a6 100644 --- a/third_party/blink/renderer/core/html/html_capability_element_base_test.cc +++ b/third_party/blink/renderer/core/html/html_capability_element_base_test.cc @@ -296,7 +296,6 @@ } GetDocument().body()->AppendChild(permission_element); - GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest); GetDocument().View()->UpdateAllLifecyclePhasesForTest(); return permission_element; } @@ -1637,6 +1636,61 @@ } }; +TEST_F(HTMLCapabilityElementBaseIntersectionTest, + MovePEPCFromIframeAndDestroyIframe) { + GetDocument().GetSettings()->SetDefaultFontSize(12); + SimRequest main_resource("https://example.test/", "text/html"); + SimRequest iframe_resource("https://example.test/foo.html", "text/html"); + LoadURL("https://example.test/"); + main_resource.Complete(R"HTML( + <body> + <style> + #occluder { + position:absolute; + left:0; + top:0; + width:100px; + height:100px; + background:black; + } + #iframe { + position:absolute; + left:0; + top:150px; + } + </style> + <div id="occluder"></div> + <iframe id="iframe" src='https://example.test/foo.html' allow="camera *"> + </iframe> + </body> + )HTML"); + iframe_resource.Complete(R"HTML( + <!DOCTYPE html><usermedia id='camera' type='camera'></usermedia> + )HTML"); + + Compositor().BeginFrame(); + + auto* subframe = To<WebLocalFrameImpl>(MainFrame().FirstChild())->GetFrame(); + auto* permission_element = static_cast<HTMLCapabilityElementBase*>( + subframe->GetDocument()->getElementById(AtomicString("camera"))); + DeferredChecker checker1(permission_element); + checker1.CheckClickingEnabledAfterDelay(kDefaultTimeout, + /*expected_enabled*/ true); + + // Move PEPC to main document and remove iframe + auto& main_document = *MainFrame().GetFrame()->GetDocument(); + main_document.body()->AppendChild(permission_element); + main_document.getElementById(AtomicString("iframe"))->remove(); + + Compositor().BeginFrame(); + + // Verify it is occluded and clicking is disabled. + WaitForIntersectionVisibilityChanged( + permission_element, + HTMLCapabilityElementBase::IntersectionVisibility::kOccludedOrDistorted); + EXPECT_FALSE(permission_element->IsClickingEnabled()); +} + TEST_F(HTMLCapabilityElementBaseIntersectionTest, IntersectionChanged) { GetDocument().GetSettings()->SetDefaultFontSize(12); SimRequest main_resource("https://example.test/", "text/html");
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/third_party/blink/renderer/core/html/html_capability_element_base_test.cc b/third_party/blink/renderer/core/html/html_capability_element_base_test.cc
index 2886eaf8..bcaca0a6 100644
--- a/third_party/blink/renderer/core/html/html_capability_element_base_test.cc
+++ b/third_party/blink/renderer/core/html/html_capability_element_base_test.cc
@@ -296,7 +296,6 @@
}
GetDocument().body()->AppendChild(permission_element);
- GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
GetDocument().View()->UpdateAllLifecyclePhasesForTest();
return permission_element;
}
@@ -1637,6 +1636,61 @@
}
};
+TEST_F(HTMLCapabilityElementBaseIntersectionTest,
+ MovePEPCFromIframeAndDestroyIframe) {
+ GetDocument().GetSettings()->SetDefaultFontSize(12);
+ SimRequest main_resource("https://example.test/", "text/html");
+ SimRequest iframe_resource("https://example.test/foo.html", "text/html");
+ LoadURL("https://example.test/");
+ main_resource.Complete(R"HTML(
+ <body>
+ <style>
+ #occluder {
+ position:absolute;
+ left:0;
+ top:0;
+ width:100px;
+ height:100px;
+ background:black;
+ }
+ #iframe {
+ position:absolute;
+ left:0;
+ top:150px;
+ }
+ </style>
+ <div id="occluder"></div>
+ <iframe id="iframe" src='https://example.test/foo.html' allow="camera *">
+ </iframe>
+ </body>
+ )HTML");
+ iframe_resource.Complete(R"HTML(
+ <!DOCTYPE html><usermedia id='camera' type='camera'></usermedia>
+ )HTML");
+
+ Compositor().BeginFrame();
+
+ auto* subframe = To<WebLocalFrameImpl>(MainFrame().FirstChild())->GetFrame();
+ auto* permission_element = static_cast<HTMLCapabilityElementBase*>(
+ subframe->GetDocument()->getElementById(AtomicString("camera")));
+ DeferredChecker checker1(permission_element);
+ checker1.CheckClickingEnabledAfterDelay(kDefaultTimeout,
+ /*expected_enabled*/ true);
+
+ // Move PEPC to main document and remove iframe
+ auto& main_document = *MainFrame().GetFrame()->GetDocument();
+ main_document.body()->AppendChild(permission_element);
+ main_document.getElementById(AtomicString("iframe"))->remove();
+
+ Compositor().BeginFrame();
+
+ // Verify it is occluded and clicking is disabled.
+ WaitForIntersectionVisibilityChanged(
+ permission_element,
+ HTMLCapabilityElementBase::IntersectionVisibility::kOccludedOrDistorted);
+ EXPECT_FALSE(permission_element->IsClickingEnabled());
+}
+
TEST_F(HTMLCapabilityElementBaseIntersectionTest, IntersectionChanged) {
GetDocument().GetSettings()->SetDefaultFontSize(12);
SimRequest main_resource("https://example.test/", "text/html");
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.
References
On This Page