CVE-2025-12911
Overview
Background
- `<permission>` element (PEPC)
- the Page-Embedded Permission Control: a browser-rendered button (e.g.
type="camera") whose click is trusted as a user permission decision, implemented inthird_party/blink/renderer/core/html/html_permission_element.cc. - PEPC style locking
- Blink forces or clamps many CSS properties on
<permission>(borders, cursor, colors, sizes) so a page cannot make the control misleading, hide it, or disguise it. - Propagated text decoration
- under CSS Text Decoration Level 3,
text-decorationset on an ancestor “decorating box” is drawn through descendant inline text, even when the descendant itself setstext-decoration: none. Blink stores this inherited state as “base text decoration data” on theComputedStyleBuilder. - `ComputedStyleBuilder::SetBaseTextDecorationData`
- the setter for the inherited decoration list; passing
nullptrclears decorations inherited from ancestors.
Root Cause Analysis
The <permission> style-adjustment code in html_permission_element.cc locked many properties on the element’s ComputedStyleBuilder (the hunk shows SetBorderRightWidth() and ClearCursorList() next to it; the enclosing function name is not shown in the hunk). It did not clear the base text-decoration data inherited from ancestor elements. As the commit message explains, the spec would stop propagation if the element’s internal container were display: inline-box, but that does not fit PEPC’s layout, so decorations such as an underline on a parent div were drawn through the permission control’s label even though PEPC is meant to have a locked, browser-controlled appearance.
The fix tightens the lock by unconditionally calling builder.SetBaseTextDecorationData(nullptr) for every <permission> element, so ancestor decorations do not propagate. The WPT reftest text-decoration-tentative.html, with text-decoration: underline on both the parent div and permission, must now render identically to an undecorated <permission>.
Attack Path
- Page embeds a permission control
A site places
<permission type="camera">(or another type) inside a container it styles. - Ancestor sets `text-decoration`
The page applies a decoration to an ancestor, as the reftest does with
div { text-decoration: underline; }. - Decoration bleeds into the locked control Before the fix, the propagated decoration was painted over the browser-rendered label, changing the control’s appearance despite PEPC’s style restrictions.
- User is misled Decorations such as line-through or heavy, coloured lines could obscure or change the apparent meaning of the label, encouraging a permission grant the user did not intend (inferred; the patch only demonstrates an underline).
Impact Assessment
<permission> control in its own renderer, weakening PEPC’s anti-deception guarantees. The result is UI spoofing or clickjacking-style deception (inferred), not a memory-safety or sandbox issue. Exploitation needs only ordinary page content where the <permission> element is available. That depends on the PEPC feature being enabled for the page (it was gated by a flag or origin trial at the time; this is inferred, since the diff does not show the gating). It also requires the user to click the misleading control. The vendor severity is low, and the supplied metadata does not report in-the-wild exploitation.Files Changed
third_party/blink/renderer/core/html/html_permission_element.ccthird_party/blink/web_tests/external/wpt/html/semantics/permission-element/text-decoration-ref.htmlthird_party/blink/web_tests/external/wpt/html/semantics/permission-element/text-decoration-tentative.html
Audit Directions
- Propagated or non-inherited style channelsReview PEPC style locking (and other trusted browser-drawn controls) for visual effects that reach an element without being set on it: ancestor
text-decoration,filter/opacity/mask/clip-pathon ancestors,mix-blend-mode, transforms, and::first-line/::first-letterstyling. - Allowlist vs. reset gapsCompare the set of properties PEPC clamps with the full CSS property list, especially properties stored in builder fields that are not tied to a single longhand (such as base text-decoration data or applied text decorations).
- Overlay/occlusion checksMake sure the activation-time checks for
<permission>(visibility, occlusion, minimum contrast) take ancestor-applied effects into account, not only the element’s own computed style.
Patch
From 9344dfce9c3a39fd2f6757d3b20390a86f5e5298 Mon Sep 17 00:00:00 2001 From: Thomas Nguyen <[email protected]> Date: Sat, 28 Jun 2025 01:42:47 -0700 Subject: [PATCH] [PEPC] Disallow text-decoration CSS property The CSS Text Decoration Module Level 3 spec (https://drafts.csswg.org/css-text-decor-3/#decorating-box) says PEPC's internal container needs `display: inline-box`. That doesn't work with our current layout, so we'll just reset the base text-decoration to get the same result. Bug: 423670839 Change-Id: I53b574d2bc2c9e0e03b62a145cce3f682466866e Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6681790 Reviewed-by: Joey Arhar <[email protected]> Commit-Queue: Thomas Nguyen <[email protected]> Cr-Commit-Position: refs/heads/main@{#1480204} --- diff --git a/third_party/blink/renderer/core/html/html_permission_element.cc b/third_party/blink/renderer/core/html/html_permission_element.cc index 9a7084c..1e57769 100644 --- a/third_party/blink/renderer/core/html/html_permission_element.cc +++ b/third_party/blink/renderer/core/html/html_permission_element.cc @@ -959,6 +959,11 @@ builder.SetBorderRightWidth(builder.FontSize()); } + // The base `text-decoration` property must be reset for each `<permission>` + // element. This prevents any `text-decoration` from a parent element from + // being propagated to the `<permission>` element. + builder.SetBaseTextDecorationData(nullptr); + // Cursor only allows 'pointer' (default) and 'not-allowed'. No custom images. builder.ClearCursorList(); if (builder.Cursor() != ECursor::kNotAllowed) { diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/permission-element/text-decoration-ref.html b/third_party/blink/web_tests/external/wpt/html/semantics/permission-element/text-decoration-ref.html new file mode 100644 index 0000000..c420d08 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/permission-element/text-decoration-ref.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<body> + <div> + <permission type="camera"></permission> + </div> +</body> +</html> \ No newline at end of file diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/permission-element/text-decoration-tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/permission-element/text-decoration-tentative.html new file mode 100644 index 0000000..be4bd04 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/semantics/permission-element/text-decoration-tentative.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<link rel="match" href="text-decoration-ref.html"> +<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style"> +<body> + <style> + permission { + text-decoration: underline; + } + div { + text-decoration: underline; + } + </style> + <div> + <permission type="camera"></permission> + </div> +</body> +</html> \ No newline at end of file
Regression Test / PoC
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/permission-element/text-decoration-ref.html b/third_party/blink/web_tests/external/wpt/html/semantics/permission-element/text-decoration-ref.html
new file mode 100644
index 0000000..c420d08
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/permission-element/text-decoration-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<body>
+ <div>
+ <permission type="camera"></permission>
+ </div>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/permission-element/text-decoration-tentative.html b/third_party/blink/web_tests/external/wpt/html/semantics/permission-element/text-decoration-tentative.html
new file mode 100644
index 0000000..be4bd04
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/permission-element/text-decoration-tentative.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<link rel="match" href="text-decoration-ref.html">
+<link rel="help" href="https://github.com/WICG/PEPC/blob/main/explainer.md#locking-the-pepc-style">
+<body>
+ <style>
+ permission {
+ text-decoration: underline;
+ }
+ div {
+ text-decoration: underline;
+ }
+ </style>
+ <div>
+ <permission type="camera"></permission>
+ </div>
+</body>
+</html>
\ No newline at end of file
Original Bug Report
Permission element inner div with style text-decoration-line: line-through; and text-decoration-thickness can be abused if no element in the parent chain has any text-decoration-line: line-through; and text-decoration-thickness are set.
This bug is similar to https://issues.chromium.org/issues/398803201, when text-decoration-line: line-through; and text-decoration-thickness: are embedded in a tag above the <permission> tag, for example a div or something else, this affects the <permission> tag, thus covering the text in the <permission> tag. if style text-decoration-line: line-through; and text-decoration-thickness embedded directly in the <permission> tag are not affected. The impact is that sites can potentially trick users to trigger permission prompts even if the permission is currently in a DENY state for that origin. (It does not however bypass the permission prompt in any way)
references for some css that can and cannot be embedded in the <permission> tag: https://developer.chrome.com/blog/permission-element-origin-trial?hl=en