Chrome · IFrame Sandbox
CVE-2026-8563
Sandbox Escape in IFrame Sandbox
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
testthird_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-area-use-counter.html |
modified | |
testthird_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-svg-anchor-use-counter.html |
modified | |
testthird_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-use-counter.html |
modified |
Files Changed
third_party/blink/public/mojom/use_counter/metrics/web_feature.mojomthird_party/blink/renderer/core/html/html_anchor_element.ccthird_party/blink/renderer/core/svg/svg_a_element.ccthird_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-area-use-counter.htmlthird_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-svg-anchor-use-counter.htmlthird_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-use-counter.htmltools/metrics/histograms/metadata/blink/enums.xml
Patch
From d6cf22406be1252f030a6a75529bc7570fab675b Mon Sep 17 00:00:00 2001
From: Emily Stark <estark@google.com>
Date: Tue, 10 Mar 2026 08:16:16 -0700
Subject: [PATCH] Measure click events from synthesized middle-clicks
Chrome will dispatch a synthesized "click" event with {"button": 1} to
an anchor element, but per spec it is unclear whether this should be
allowed. Measure how common this is so that we can hopefully deprecate.
Bug: 40061220,40262435
Change-Id: I7643f0a38e2d43eab57c49e5a024482ac3fd1393
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7643254
Reviewed-by: Mason Freed <masonf@chromium.org>
Commit-Queue: Emily Stark <estark@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1597071}
---
diff --git a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
index cb23d2a..da550c03 100644
--- a/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
+++ b/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom
@@ -5133,6 +5133,9 @@
kHTMLInputElementTypeChangedWhileConnected = 5816,
kHTMLButtonElementTypeChangedWhileDisconnected = 5817,
kHTMLInputElementTypeChangedWhileDisconnected = 5818,
+ kSynthesizedMiddleClickAnchor = 5819,
+ kSynthesizedMiddleClickArea = 5820,
+ kSynthesizedMiddleClickSVGAnchor = 5821,
// Add new features immediately above this line. Don't change the existing
// numbers of any item, and don't reuse removed slots. Also don't add extra
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.cc b/third_party/blink/renderer/core/html/html_anchor_element.cc
index eb9ae05..ad38749 100644
--- a/third_party/blink/renderer/core/html/html_anchor_element.cc
+++ b/third_party/blink/renderer/core/html/html_anchor_element.cc
@@ -550,6 +550,22 @@
void HTMLAnchorElementBase::HandleClick(MouseEvent& event) {
event.SetDefaultHandled();
+ // It's unclear whether synthesized middle-button "click" events should be
+ // allowed to be dispatched and create a navigation. Measure how common this
+ // is to see if we can disallow it. Per Pointer Events: "The click event
+ // should only be fired for the primary pointer button (i.e., when button
+ // value is 0, buttons value is 1). Secondary buttons (like the middle or
+ // right button on a standard mouse) MUST NOT fire click events."
+ // (https://w3c.github.io/pointerevents/#dfn-click)
+ if (event.type() == event_type_names::kClick && !event.isTrusted() &&
+ event.button() ==
+ static_cast<int16_t>(WebPointerProperties::Button::kMiddle)) {
+ UseCounter::Count(GetDocument(),
+ IsA<HTMLAreaElement>(this)
+ ? WebFeature::kSynthesizedMiddleClickArea
+ : WebFeature::kSynthesizedMiddleClickAnchor);
+ }
+
LocalDOMWindow* window = GetDocument().domWindow();
if (!window)
return;
diff --git a/third_party/blink/renderer/core/svg/svg_a_element.cc b/third_party/blink/renderer/core/svg/svg_a_element.cc
index 26992db..1a4e2e8 100644
--- a/third_party/blink/renderer/core/svg/svg_a_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_a_element.cc
@@ -48,6 +48,7 @@
#include "third_party/blink/renderer/core/svg_names.h"
#include "third_party/blink/renderer/core/xlink_names.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
@@ -124,6 +125,20 @@
}
if (IsLinkClick(event)) {
+ // It's unclear whether synthesized middle-button "click" events should be
+ // allowed to be dispatched and create a navigation. Measure how common
+ // this is to see if we can disallow it. Per Pointer Events: "The click
+ // event should only be fired for the primary pointer button (i.e., when
+ // button value is 0, buttons value is 1). Secondary buttons (like the
+ // middle or right button on a standard mouse) MUST NOT fire click
+ // events." (https://w3c.github.io/pointerevents/#dfn-click)
+ if (event.type() == event_type_names::kClick && !event.isTrusted() &&
+ To<MouseEvent>(event).button() ==
+ static_cast<int16_t>(WebPointerProperties::Button::kMiddle)) {
+ UseCounter::Count(GetDocument(),
+ WebFeature::kSynthesizedMiddleClickSVGAnchor);
+ }
+
StringView url = StripLeadingAndTrailingHtmlSpaces(HrefString());
if (url.starts_with('#')) {
diff --git a/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-area-use-counter.html b/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-area-use-counter.html
new file mode 100644
index 0000000..d148cad
--- /dev/null
+++ b/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-area-use-counter.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+
+<body>
+ <map id="m" name="m">
+ <area href="" shape="default">
+ </map>
+ <img src="" usemap="#m" id="image">
+ <script>
+ const kSynthesizedMiddleClickArea = 5820;
+
+ test(function () {
+ const area = document.querySelector('area');
+
+ internals.clearUseCounter(document, kSynthesizedMiddleClickArea);
+ assert_false(internals.isUseCounted(document, kSynthesizedMiddleClickArea), "Area should not be counted initially");
+ const event = new MouseEvent('click', {
+ button: 1 // Middle button
+ });
+ area.dispatchEvent(event);
+ assert_true(internals.isUseCounted(document, kSynthesizedMiddleClickArea), "Area should be counted after synthesized middle click");
+ }, "Synthesized middle click on area should trigger UseCounter");
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-svg-anchor-use-counter.html b/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-svg-anchor-use-counter.html
new file mode 100644
index 0000000..3596910
--- /dev/null
+++ b/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-svg-anchor-use-counter.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+
+<body>
+ <svg xmlns="http://www.w3.org/2000/svg">
+ <a href="" id="svglink"><text>link</text></a>
+ </svg>
+ <script>
+ const kSynthesizedMiddleClickSVGAnchor = 5821;
+
+ test(function () {
+ const link = document.getElementById('svglink');
+
+ internals.clearUseCounter(document, kSynthesizedMiddleClickSVGAnchor);
+ assert_false(internals.isUseCounted(document, kSynthesizedMiddleClickSVGAnchor), "SVG anchor should not be counted initially");
+ const event = new MouseEvent('click', {
+ button: 1 // Middle button
+ });
+ link.dispatchEvent(event);
+ assert_true(internals.isUseCounted(document, kSynthesizedMiddleClickSVGAnchor), "SVG anchor should be counted after synthesized middle click");
+ }, "Synthesized middle click on SVG anchor should trigger UseCounter");
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-use-counter.html b/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-use-counter.html
new file mode 100644
index 0000000..cf05a372
--- /dev/null
+++ b/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-use-counter.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+
+<body>
+ <a id="link" href="#">Link</a>
+ <script>
+ const kSynthesizedMiddleClickAnchor = 5819;
+
+ test(function () {
+ const link = document.getElementById('link');
+
+ internals.clearUseCounter(document, kSynthesizedMiddleClickAnchor);
+ assert_false(internals.isUseCounted(document, kSynthesizedMiddleClickAnchor), "Should not be counted initially");
+ const event = new MouseEvent('click', {
+ button: 1 // Middle button
+ });
+ link.dispatchEvent(event);
+ assert_true(internals.isUseCounted(document, kSynthesizedMiddleClickAnchor), "Should be counted after synthesized middle click");
+ }, "Synthesized middle click on anchor should trigger UseCounter");
+
+ test(function () {
+ const link = document.getElementById('link');
+
+ internals.clearUseCounter(document, kSynthesizedMiddleClickAnchor);
+ const event = new MouseEvent('click', {
+ button: 0 // Left button
+ });
+ link.dispatchEvent(event);
+ assert_false(internals.isUseCounted(document, kSynthesizedMiddleClickAnchor), "Should not be counted after synthesized left click");
+ }, "Synthesized left click on anchor should not trigger UseCounter");
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/tools/metrics/histograms/metadata/blink/enums.xml b/tools/metrics/histograms/metadata/blink/enums.xml
index 1ec1baa..f1d550a 100644
--- a/tools/metrics/histograms/metadata/blink/enums.xml
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-area-use-counter.html b/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-area-use-counter.html
new file mode 100644
index 0000000..d148cad
--- /dev/null
+++ b/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-area-use-counter.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+
+<body>
+ <map id="m" name="m">
+ <area href="" shape="default">
+ </map>
+ <img src="" usemap="#m" id="image">
+ <script>
+ const kSynthesizedMiddleClickArea = 5820;
+
+ test(function () {
+ const area = document.querySelector('area');
+
+ internals.clearUseCounter(document, kSynthesizedMiddleClickArea);
+ assert_false(internals.isUseCounted(document, kSynthesizedMiddleClickArea), "Area should not be counted initially");
+ const event = new MouseEvent('click', {
+ button: 1 // Middle button
+ });
+ area.dispatchEvent(event);
+ assert_true(internals.isUseCounted(document, kSynthesizedMiddleClickArea), "Area should be counted after synthesized middle click");
+ }, "Synthesized middle click on area should trigger UseCounter");
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-svg-anchor-use-counter.html b/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-svg-anchor-use-counter.html
new file mode 100644
index 0000000..3596910
--- /dev/null
+++ b/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-svg-anchor-use-counter.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+
+<body>
+ <svg xmlns="http://www.w3.org/2000/svg">
+ <a href="" id="svglink"><text>link</text></a>
+ </svg>
+ <script>
+ const kSynthesizedMiddleClickSVGAnchor = 5821;
+
+ test(function () {
+ const link = document.getElementById('svglink');
+
+ internals.clearUseCounter(document, kSynthesizedMiddleClickSVGAnchor);
+ assert_false(internals.isUseCounted(document, kSynthesizedMiddleClickSVGAnchor), "SVG anchor should not be counted initially");
+ const event = new MouseEvent('click', {
+ button: 1 // Middle button
+ });
+ link.dispatchEvent(event);
+ assert_true(internals.isUseCounted(document, kSynthesizedMiddleClickSVGAnchor), "SVG anchor should be counted after synthesized middle click");
+ }, "Synthesized middle click on SVG anchor should trigger UseCounter");
+ </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-use-counter.html b/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-use-counter.html
new file mode 100644
index 0000000..cf05a372
--- /dev/null
+++ b/third_party/blink/web_tests/fast/events/pointerevents/synthesized-middle-click-use-counter.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+
+<body>
+ <a id="link" href="#">Link</a>
+ <script>
+ const kSynthesizedMiddleClickAnchor = 5819;
+
+ test(function () {
+ const link = document.getElementById('link');
+
+ internals.clearUseCounter(document, kSynthesizedMiddleClickAnchor);
+ assert_false(internals.isUseCounted(document, kSynthesizedMiddleClickAnchor), "Should not be counted initially");
+ const event = new MouseEvent('click', {
+ button: 1 // Middle button
+ });
+ link.dispatchEvent(event);
+ assert_true(internals.isUseCounted(document, kSynthesizedMiddleClickAnchor), "Should be counted after synthesized middle click");
+ }, "Synthesized middle click on anchor should trigger UseCounter");
+
+ test(function () {
+ const link = document.getElementById('link');
+
+ internals.clearUseCounter(document, kSynthesizedMiddleClickAnchor);
+ const event = new MouseEvent('click', {
+ button: 0 // Left button
+ });
+ link.dispatchEvent(event);
+ assert_false(internals.isUseCounted(document, kSynthesizedMiddleClickAnchor), "Should not be counted after synthesized left click");
+ }, "Synthesized left click on anchor should not trigger UseCounter");
+ </script>
+</body>
+</html>
\ No newline at end of file
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