Medium chrome Spoofing 🔧 Commit mapped

Overview

Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUI misrepresentation in Paint
DescriptionUI misrepresentation in Paint
ComponentPaint
Bug ClassSpoofing
Tracker514078734
Fix commita80f58655f77 (chromium/src) +49/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-10-06

Changed Functions

FunctionChangeNotes
TEST_P
third_party/blink/renderer/core/paint/compositing/compositing_test.cc
modified

Files Changed

  • third_party/blink/renderer/core/paint/compositing/compositing_test.cc
  • third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc
From a80f58655f77af72c9127fdc16fa7cf0594b5fc9 Mon Sep 17 00:00:00 2001
From: Philip Rogers <[email protected]>
Date: Fri, 11 Sep 2026 15:51:27 -0700
Subject: [PATCH] Prevent merging sticky layers across non-2d-translation transforms

Sticky layers cannot be merged across non-2D-translation transforms
because the compositor sticky offset applied to the merged layer would
not correctly account for intermediate transforms. This patch adds a
check to ensure both nodes share the same RootOf2dTranslation.

Fixed: 514078734
Change-Id: I1eac45e1539c975b74ff255c7a0ad1007e53ec8e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8393871
Reviewed-by: Xianzhu Wang <[email protected]>
Commit-Queue: Philip Rogers <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1696682}
---
diff --git a/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc b/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc
index 4914a45..f5439ac5 100644
--- a/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/transform_paint_property_node.cc
@@ -184,7 +184,8 @@
       UnaliasedParent()->NearestDirectlyCompositedAncestor() !=
           other.UnaliasedParent()->NearestDirectlyCompositedAncestor() ||
       &NearestScrollTranslationNode() !=
-          &other.NearestScrollTranslationNode()) {
+          &other.NearestScrollTranslationNode() ||
+      RootOf2dTranslation() != other.RootOf2dTranslation()) {
     return cc::StickyPositionConstraint::CanMergeResult::kCannotMerge;
   }
 
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_test.cc b/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
index 5254842..95b44618 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
@@ -1257,6 +1257,53 @@
   EXPECT_TRUE(CcLayerByDOMElementId("d5"));
 }
 
+TEST_P(CompositingTest, DontMergeStickyLayersAcrossNon2dTranslationTransform) {
+  InitializeWithHTML(*WebView()->MainFrameImpl()->GetFrame(), R"HTML(
+    <style>
+      .scroller {
+        width: 200px;
+        height: 200px;
+        overflow: scroll;
+        position: relative;
+      }
+      .wrapper {
+        position: absolute;
+        top: 0;
+        left: 0;
+        width: 100px;
+        height: 400px;
+        visibility: hidden;
+      }
+      .sticky {
+        position: sticky;
+        top: 0;
+        width: 100px;
+        height: 100px;
+        visibility: visible;
+      }
+    </style>
+    <div class="scroller">
+      <div style="height: 400px"></div>
+      <div class="wrapper">
+        <div id="a" class="sticky"></div>
+      </div>
+      <div class="wrapper" style="transform: rotate(1deg)">
+        <div id="b" class="sticky"></div>
+      </div>
+    </div>
+  )HTML");
+
+  // The two sticky elements have matching sticky constraints, but `b` is under
+  // a non-2d-translation transform. They should not be merged because the
+  // compositor sticky offset applied to a merged layer would not correctly
+  // account for the transform above `b`.
+  cc::Layer* a = CcLayerByDOMElementId("a");
+  ASSERT_TRUE(a);
+  cc::Layer* b = CcLayerByDOMElementId("b");
+  ASSERT_TRUE(b);
+  EXPECT_NE(a->transform_tree_index(), b->transform_tree_index());
+}
+
 TEST_P(CompositingTest, DontCompositeStickyAlongNonScrollableAxis) {
   InitializeWithHTML(*WebView()->MainFrameImpl()->GetFrame(), R"HTML(
     <style>
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_test.cc b/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
index 5254842..95b44618 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_test.cc
@@ -1257,6 +1257,53 @@
   EXPECT_TRUE(CcLayerByDOMElementId("d5"));
 }
 
+TEST_P(CompositingTest, DontMergeStickyLayersAcrossNon2dTranslationTransform) {
+  InitializeWithHTML(*WebView()->MainFrameImpl()->GetFrame(), R"HTML(
+    <style>
+      .scroller {
+        width: 200px;
+        height: 200px;
+        overflow: scroll;
+        position: relative;
+      }
+      .wrapper {
+        position: absolute;
+        top: 0;
+        left: 0;
+        width: 100px;
+        height: 400px;
+        visibility: hidden;
+      }
+      .sticky {
+        position: sticky;
+        top: 0;
+        width: 100px;
+        height: 100px;
+        visibility: visible;
+      }
+    </style>
+    <div class="scroller">
+      <div style="height: 400px"></div>
+      <div class="wrapper">
+        <div id="a" class="sticky"></div>
+      </div>
+      <div class="wrapper" style="transform: rotate(1deg)">
+        <div id="b" class="sticky"></div>
+      </div>
+    </div>
+  )HTML");
+
+  // The two sticky elements have matching sticky constraints, but `b` is under
+  // a non-2d-translation transform. They should not be merged because the
+  // compositor sticky offset applied to a merged layer would not correctly
+  // account for the transform above `b`.
+  cc::Layer* a = CcLayerByDOMElementId("a");
+  ASSERT_TRUE(a);
+  cc::Layer* b = CcLayerByDOMElementId("b");
+  ASSERT_TRUE(b);
+  EXPECT_NE(a->transform_tree_index(), b->transform_tree_index());
+}
+
 TEST_P(CompositingTest, DontCompositeStickyAlongNonScrollableAxis) {
   InitializeWithHTML(*WebView()->MainFrameImpl()->GetFrame(), R"HTML(
     <style>
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.