CVE-2026-106302
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
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_test.cc
Patch
From 1660791100160664a5358b9b79660f7791001b34 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen <[email protected]> Date: Fri, 11 Sep 2026 14:04:19 -0700 Subject: [PATCH] [CE]: Reset inherited writing-mode on capability elements GetCascadeFilter() rejects declarations of properties that are not on the kValidForPermissionElement allow-list, but inherited values are copied from the parent style before the cascade runs and so bypass the filter. AdjustStyle() already resets a few such properties; add writing-mode, text-orientation and text-combine-upright to that list and call UpdateFontOrientation() to keep the font in sync. We should not allow those values to be inherited. Fixed: 514071472 Change-Id: I565e4d399400bc0eb6a572d256f49a76f66a11bb Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8303435 Commit-Queue: Joey Arhar <[email protected]> Auto-Submit: Thomas Nguyen <[email protected]> Reviewed-by: Joey Arhar <[email protected]> Cr-Commit-Position: refs/heads/main@{#1696586} --- 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 34c053bc..53c0832 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 @@ -921,14 +921,19 @@ } } - // These webkit-prefixed properties are not supported by the permission - // element. But since they are inherited by default, they are passed through - // to the internal permission text span, even if they're not on the list of - // allowed CSS properties. + // These properties are not supported by the permission element. But since + // they are inherited by default, they are passed through to the internal + // permission text span, even if they're not on the list of allowed CSS + // properties. // Reset them here to avoid any side effects. builder.ResetTextStrokeWidth(); builder.ResetTextFillColor(); builder.ResetTextStrokeColor(); + // TODO(crbug.com/560222073): Handle vertical writing mode properly. + builder.ResetWritingMode(); + builder.ResetTextOrientation(); + builder.ResetTextCombine(); + builder.UpdateFontOrientation(); // To prevent CSS :visited history leaks and ensure the button remains // fully legible and active in all states, we force the element to pretend 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 c5c6a849..2d282ec 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 @@ -1078,6 +1078,35 @@ style->VisitedDependentColor(GetCSSPropertyBackgroundColor())); } +TEST_F(HTMLCapabilityElementBaseSimTest, InheritedVerticalWritingModeIsReset) { + // Properties that are not on the allow-list can still be inherited from a + // parent element. Verify that an inherited vertical writing-mode is reset so + // that the size constraints, which assume a horizontal inline axis, keep the + // text inside the element's bounds. + GetDocument().body()->setAttribute( + html_names::kStyleAttr, + AtomicString("writing-mode: vertical-rl; text-orientation: upright;")); + auto* permission_element = CreatePermissionElement(GetDocument(), "camera"); + GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest); + + const ComputedStyle* style = permission_element->GetComputedStyle(); + ASSERT_TRUE(style); + EXPECT_EQ(WritingMode::kHorizontalTb, style->GetWritingMode()); + EXPECT_EQ(ETextOrientation::kMixed, style->GetTextOrientation()); + EXPECT_EQ(FontOrientation::kHorizontal, + style->GetFontDescription().Orientation()); + + auto* text_span = + permission_element->permission_text_span_for_testing().Get(); + ASSERT_TRUE(text_span); + gfx::Rect element_rect = + permission_element->GetBoundingClientRect()->ToEnclosingRect(); + gfx::Rect text_rect = text_span->GetBoundingClientRect()->ToEnclosingRect(); + EXPECT_TRUE(element_rect.Contains(text_rect)) + << "element=" << element_rect.ToString() + << " text=" << text_rect.ToString(); +} + TEST_F(HTMLCapabilityElementBaseSimTest, FontSizeCanDisableElement) { GetDocument().GetSettings()->SetDefaultFontSize(12); auto* permission_element = CreatePermissionElement(GetDocument(), "camera");
Regression Test / PoC
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 c5c6a849..2d282ec 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
@@ -1078,6 +1078,35 @@
style->VisitedDependentColor(GetCSSPropertyBackgroundColor()));
}
+TEST_F(HTMLCapabilityElementBaseSimTest, InheritedVerticalWritingModeIsReset) {
+ // Properties that are not on the allow-list can still be inherited from a
+ // parent element. Verify that an inherited vertical writing-mode is reset so
+ // that the size constraints, which assume a horizontal inline axis, keep the
+ // text inside the element's bounds.
+ GetDocument().body()->setAttribute(
+ html_names::kStyleAttr,
+ AtomicString("writing-mode: vertical-rl; text-orientation: upright;"));
+ auto* permission_element = CreatePermissionElement(GetDocument(), "camera");
+ GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
+
+ const ComputedStyle* style = permission_element->GetComputedStyle();
+ ASSERT_TRUE(style);
+ EXPECT_EQ(WritingMode::kHorizontalTb, style->GetWritingMode());
+ EXPECT_EQ(ETextOrientation::kMixed, style->GetTextOrientation());
+ EXPECT_EQ(FontOrientation::kHorizontal,
+ style->GetFontDescription().Orientation());
+
+ auto* text_span =
+ permission_element->permission_text_span_for_testing().Get();
+ ASSERT_TRUE(text_span);
+ gfx::Rect element_rect =
+ permission_element->GetBoundingClientRect()->ToEnclosingRect();
+ gfx::Rect text_rect = text_span->GetBoundingClientRect()->ToEnclosingRect();
+ EXPECT_TRUE(element_rect.Contains(text_rect))
+ << "element=" << element_rect.ToString()
+ << " text=" << text_rect.ToString();
+}
+
TEST_F(HTMLCapabilityElementBaseSimTest, FontSizeCanDisableElement) {
GetDocument().GetSettings()->SetDefaultFontSize(12);
auto* permission_element = CreatePermissionElement(GetDocument(), "camera");
Original Bug Report
PEPC writing-mode inheritance bypass enables UI redress attacks
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: The Page Embedded Permission Control (PEPC) fails to restrict inherited CSS properties like ‘writing-mode’, allowing them to bypass the ‘CascadeFilter’. This can cause the element’s label to overflow its physically clamped border box without triggering security validation or visibility errors, potentially enabling UI redress attacks.
Affected files:
third_party/blink/renderer/core/html/html_capability_element_base.ccthird_party/blink/renderer/core/html/resources/capability_element.cssthird_party/blink/renderer/core/html/html_permission_element_utils.ccthird_party/blink/renderer/core/css/resolver/style_cascade.ccthird_party/blink/renderer/core/css/resolver/style_resolver.cc
Estimated timestamp from git blame: 2024-03-01
Summary
The Page Embedded Permission Control (PEPC) implementation contains a logic flaw where certain inherited CSS properties—specifically writing-mode, text-orientation, direction, and text-combine-upright—are not properly restricted or reset. An attacker could potentially use these properties to cause the PEPC label text to render vertically and overflow its physically clamped border box. Because the PEPC’s security validation and visibility tracking only consider the border box, the overflowed text can be hidden or spoofed, potentially leading to a UI redress (clickjacking) attack.
Root Cause Analysis
The vulnerability stems from how PEPC applies CSS property restrictions:
-
CascadeFilter Limitation:
HTMLCapabilityElementBase::GetCascadeFilter(html_capability_element_base.cc:409) returns a filter that gates declarations during the CSS cascade. However, in Blink’s style resolution, inherited properties are copied from the parent before the cascade filter is applied. The filter does not prevent properties from being inherited. -
Incomplete Property Reset: While some inherited properties (like
-webkit-text-stroke-width) are manually reset inHTMLCapabilityElementBase::AdjustStyle(cc:714),writing-mode,text-orientation,direction, andtext-combine-uprightare not included in the reset list. -
Physical Sizing Clamps: In
AdjustStyle, the element’s physicalmax-heightis hard-clamped to a multiple of the font size (typically 3x) regardless of the writing mode (cc:772). -
Layout Mechanics: When
writing-mode: vertical-rlis inherited, the label text flows vertically. Its intrinsic height will far exceed the 48px physical clamp. Since the element hasoverflow: visible(the default), the text overflows the border box. -
Security Invariant Bypass:
IsStyleValid()(cc:1409) validates display, color, contrast, and font size but does not validate writing-mode or detect layout overflow.- The Intersection Observer V2 used for visibility tracking (cc:335) only monitors the element’s border box for occlusion and visibility (intersection_geometry.cc:121). It does not detect that the label (ink overflow) is outside the box or potentially occluded.
Potential Attack Scenario
Note: These are potential steps as our current tooling has not executed this code.
- An attacker wraps a PEPC (e.g.,
<geolocation>) in a container withstyle="writing-mode: vertical-rl". - The PEPC inherits the vertical writing mode. Its label renders vertically and overflows the ~48px-tall border box.
- The attacker occludes the overflowed real label (e.g., by placing it under another element that does not intersect the PEPC’s border box, thus avoiding detection by Intersection Observer V2).
- The attacker positions a decoy label (e.g., “Click for Prize”) next to the small 48px click target.
- A user, misled by the decoy label, clicks the target area.
- Because the border box itself is visible and not occluded, the PEPC processes the click and triggers a browser-anchored permission prompt.
Suggested Fix
- In
HTMLCapabilityElementBase::AdjustStyle, explicitly resetwriting-mode,text-orientation,direction, andtext-combine-uprightto their initial values. - In
HTMLCapabilityElementBase::IsStyleValid, verify that thewriting-modeishorizontal-tb(or the default for the platform) and ensure no unexpected layout overflow is present.
Evaluated with Chrome root at commit: 1a8d40fc44df2088d5945c0bf53584038aa1614a
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.
- https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/html_capability_element_base.cc;l=1409
- https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/html_capability_element_base.cc;l=335
- https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/html_capability_element_base.cc;l=409
- https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/html_capability_element_base.cc;l=714
- https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/html_capability_element_base.cc;l=772
- https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/intersection_observer/intersection_geometry.cc;l=121