Low watch CVSS 6.5 chrome Info Disclosure 🔧 Commit mapped

Overview

Low
Severity
6.5
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactObservable discrepancy in SVG
DescriptionObservable discrepancy in SVG
ComponentSVG
Sub-componentHiC
Bug ClassInfo Disclosure
Action tierwatch — information disclosure — security-relevant, below the RCE-class bar
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker514489101
Fix commit07625009a5ee (chromium/src) +339/-0
CWECWE-203
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-05-19 (per vendor advisory)
Fix landed2026-08-12 (public git)
Disclosed2026-09-08
Patch gap27 days — fix public in source before the advisory

Background

HTML-in-canvas (`HiC`) / `drawElementImage`
a WICG feature that paints a live DOM element into a <canvas>, which must render “privacy-preserving” so it cannot leak visited-link state or form autofill back to script.
`PaintFlag::kPrivacyPreserving`
a paint flag set on the paint pass used for drawElementImage, signalling that painting must suppress history- and autofill-derived content.
SVG paint resource
a <linearGradient>, <radialGradient>, or <pattern> referenced from a fill/stroke via url(#id); a gradient stop can resolve currentColor (which reflects :visited) and a <pattern> can hold arbitrary DOM including autofilled forms.
`IsInCanvasSubtree()`
a flag marking an element as living inside the canvas’s fallback/layout subtree, which is the scope the privacy-preserving machinery actually covers.

Root Cause Analysis

When an element is rendered into a canvas through drawElementImage, the paint pass runs with PaintFlag::kPrivacyPreserving so that visited-link colors and autofill content are neutralized. However, an SVG shape inside the canvas subtree can reference a paint resource (url(#id)) whose defining element lives outside the canvas subtree. Those external elements are never marked IsInCanvasSubtree(), so the privacy-preserving substitutions (unvisited colors, suppressed autofill) do not apply to them, yet the pre-patch code applied their shader anyway via uri_resource->ApplyShader(...). The invariant violated is that every input to a privacy-preserving render must itself be within the privacy-scoped subtree.

The fix adds an early return false when kPrivacyPreserving is set and !uri_resource->GetElement()->IsInCanvasSubtree(), so the out-of-subtree resource is skipped (the paint falls back to no/transparent fill) and cannot smuggle privileged pixels into the canvas.

Key insight
The core mistake was scoping the privacy protection to the canvas subtree while letting shapes in that subtree pull in SVG paint resources defined outside it, which were never subject to those protections; the fix closes the gap by refusing any paint resource whose element is not IsInCanvasSubtree() during a privacy-preserving paint.

Attack Path

  1. Define a privileged resource outside the subtree the attacker places a <linearGradient>/<radialGradient> whose stops use stop-color="currentColor" inside an <a> styled with a different :visited color (or a <pattern> containing autofillable DOM), outside any canvas.
  2. Reference it from inside the canvas subtree a <rect fill="url(#grad-outside)"> sits inside a <canvas layoutsubtree> child element, so the reference crosses the subtree boundary.
  3. Trigger the privacy-preserving paint script calls context.drawElementImage(child, 0, 0), which paints the child with PaintFlag::kPrivacyPreserving; pre-patch, the external gradient/pattern shader is still applied and resolves currentColor from the real (possibly visited) state.
  4. Read back the pixels context.getImageData(...) returns colors that differ depending on the link’s visited state (or reveal autofill), letting script observe browsing history / autofilled data — the observable discrepancy. (Broader escalation beyond history/autofill disclosure not shown by the patch.)

Impact Assessment

An attacker running web content in the renderer can read back canvas pixels to learn whether a link was visited or to reveal autofill content that the privacy-preserving canvas path was supposed to hide, i.e. cross-origin/history information disclosure. Preconditions are the HTML-in-canvas drawElementImage feature being available and an SVG paint resource defined outside the canvas subtree but referenced from within it. The vendor advisory rates this low severity and does not report in-the-wild exploitation; NVD scores it CVSS 6.5.

Changed Functions

FunctionChangeNotes
promise_test
third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-linear-gradient-outside-subtree-ignored.tentative.html
modified
promise_test
third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-pattern-outside-subtree-ignored.tentative.html
modified
promise_test
third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-radial-gradient-outside-subtree-ignored.tentative.html
modified
promise_test
third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-color-ignored.tentative.html
modified
promise_test
third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-currentcolor-ignored.tentative.html
modified
promise_test
third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-decoration-color-ignored.tentative.html
modified

Files Changed

  • third_party/blink/renderer/core/paint/svg_object_painter.cc
  • third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link/visited-link-color-ignored.tentative.html
  • third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link/visited-link-svg-fill-stroke-color-ignored.tentative.html
  • third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-linear-gradient-outside-subtree-ignored.tentative.html
  • third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-radial-gradient-outside-subtree-ignored.tentative.html
  • third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link/visited-link-svg-linear-gradiant-ignored.tentative.html
  • third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link/visited-link-svg-pattern-ignored.tentative.html
  • third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link/visited-link-currentcolor-ignored.tentative.html
  • third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link/visited-link-svg-radiant-gradiant-ignored.tentative.html
  • third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-pattern-outside-subtree-ignored.tentative.html
  • third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link/visited-link-decoration-color-ignored.tentative.html

Audit Directions

  • Cross-subtree resource references under a privacy flag
    audit every place that resolves url(#id) references (SVG paint servers, masks, clip-paths, filters, markers, <use>) during a kPrivacyPreserving paint to confirm the target’s subtree membership is checked, not just the referencing element’s.
  • Scope of `IsInCanvasSubtree()` gating
    search for paint/style code that applies privacy substitutions based on the element being painted while pulling in secondary resources or DOM whose subtree status is never re-validated (the filed follow-up on SVG <use> is one such case).
  • currentColor / visited-state leakage channels
    review paths where currentColor, :visited-derived colors, or autofilled form content can be resolved from elements outside the privacy scope and end up in a readable buffer (canvas, image snapshot, generated content).
From 07625009a5eefe24a3511b87fee9142e4d7a71a3 Mon Sep 17 00:00:00 2001
From: Stephen Chenney <schenney@chromium.org>
Date: Wed, 12 Aug 2026 13:22:26 -0700
Subject: [PATCH] [HiC] Disallow non-subtree SVG paint resources

SVG Paint Resources may use visited link colors, or the
<pattern> element may contain arbitrary DOM content, including
forms with autofill. When defined outside the canvas subtree
these elements are not marked as being inside the subtree, which
defeats various privacy preserving measures. So disallow the
use of resources from outside the canvas subtree when inside the
canvas subtree.

Add tests and start to re-organize the privacy tests to make it
easier to see what areas we are testing.

A bug has been filed to verify the behavior of SVG <use> elements.

Fixed: 514489101
Change-Id: Ife76a6c02aaa2c3eefdb604343b849a213657900
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8058744
Commit-Queue: Stephen Chenney <schenney@chromium.org>
Reviewed-by: Stefan Zager <szager@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1678269}
---
diff --git a/third_party/blink/renderer/core/paint/svg_object_painter.cc b/third_party/blink/renderer/core/paint/svg_object_painter.cc
index 35863f4..7b078882 100644
--- a/third_party/blink/renderer/core/paint/svg_object_painter.cc
+++ b/third_party/blink/renderer/core/paint/svg_object_painter.cc
@@ -31,6 +31,11 @@
     return false;
   }
 
+  if (paint_flags & PaintFlag::kPrivacyPreserving &&
+      !uri_resource->GetElement()->IsInCanvasSubtree()) {
+    return false;
+  }
+
   AutoDarkMode auto_dark_mode(PaintAutoDarkMode(
       context_paint.object.StyleRef(), DarkModeFilter::ElementRole::kSVG));
   if (!uri_resource->ApplyShader(
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-linear-gradient-outside-subtree-ignored.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-linear-gradient-outside-subtree-ignored.tentative.html
new file mode 100644
index 0000000..da2ee27
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-linear-gradient-outside-subtree-ignored.tentative.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>drawElementImage does not use SVG resources from outside the subtree</title>
+  <script src='/resources/testharness.js'></script>
+  <script src='/resources/testharnessreport.js'></script>
+  <script src="/html/canvas/resources/wait-for-canvas-paint.js"></script>
+  <style>
+    a {
+      color: blue;
+    }
+    a:visited {
+      color: red;
+    }
+    canvas {
+      background-color: green;
+    }
+  </style>
+</head>
+<body>
+  <a href="">
+    <svg width="0" height="0">
+      <defs>
+        <linearGradient id="grad-outside">
+          <stop offset="0" stop-color="currentColor"/>
+          <stop offset="1" stop-color="currentColor"/>
+        </linearGradient>
+      </defs>
+    </svg>
+  </a>
+
+  <canvas id="canvas" width="100" height="100" layoutsubtree>
+    <div id="child">
+      <svg width="100" height="100">
+        <rect x="0" y="0" width="100" height="100" fill="url(#grad-outside)"/>
+      </svg>
+    </div>
+  </canvas>
+
+  <script>
+    window.onload = () => {
+      promise_test(async function(t) {
+        await waitForCanvasPaint(canvas);
+
+        var context = canvas.getContext("2d");
+
+        context.fillStyle = 'green';
+        context.fillRect(0, 0, 100, 100);
+
+        // Draw the element image
+        context.drawElementImage(child, 0, 0);
+
+        // The canvas should ignore the gradient and use transparent black.
+        let pixel = context.getImageData(50, 50, 1, 1).data;
+        assert_false(pixel[0] > 0, "The canvas should not use the gradient.");
+        assert_true(pixel[1] > 0, "The canvas should not use the gradient.");
+        assert_false(pixel[2] > 0, "The canvas should not use the gradient.");
+      });
+    };
+  </script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-pattern-outside-subtree-ignored.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-pattern-outside-subtree-ignored.tentative.html
new file mode 100644
index 0000000..71ab5f6d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-pattern-outside-subtree-ignored.tentative.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>drawElementImage does not use SVG patterns outside the subtree</title>
+  <link rel="help" href="https://github.com/WICG/html-in-canvas">
+  <script src='/resources/testharness.js'></script>
+  <script src='/resources/testharnessreport.js'></script>
+  <script src="/html/canvas/resources/wait-for-canvas-paint.js"></script>
+</head>
+<body>
+  <svg width="0" height="0">
+    <defs>
+      <pattern id="pattern" patternUnits="userSpaceOnUse" viewBox="0 0 100 100" width="100" height="100">
+        <image href="/images/red-100x100.png" x="0" y="0" width="100" height="100" preserveAspectRatio="none"/>
+      </pattern>
+    </defs>
+  </svg>
+
+  <canvas id="canvas" width="100" height="100" layoutsubtree>
+    <svg id=child width="100" height="100">
+      <rect x="0" y="0" width="100" height="100" fill="url(#pattern)"/>
+    </svg>
+  </canvas>
+
+  <script>
+    window.onload = () => {
+      promise_test(async function(t) {
+        const preloadImage = (url) => new Promise((resolve, reject) => {
+          const img = new Image();
+          img.onload = () => resolve(img);
+          img.onerror = () => reject(new Error(`Failed to load image: ${url}`));
+          img.src = url;
+        });
+
+        const imageEl = document.querySelector('#pattern image');
+        await Promise.all([
+          preloadImage(imageEl.getAttribute('href')),
+        ]);
+
+        await waitForCanvasPaint(canvas);
+        var ctx = canvas.getContext('2d');
+        ctx.fillStyle = 'green';
+        ctx.fillRect(0, 0, 100, 100);
+        ctx.drawElementImage(child, 0, 0);
+
+        // The canvas should ignore the gradient and use transparent black.
+        let pixel = ctx.getImageData(50, 50, 1, 1).data;
+        assert_false(pixel[0] > 0, "The canvas should not use the pattern.");
+        assert_true(pixel[1] > 0, "The canvas should not use the pattern.");
+        assert_false(pixel[2] > 0, "The canvas should not use the pattern.");
+      });
+    }
+  </script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-radial-gradient-outside-subtree-ignored.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-radial-gradient-outside-subtree-ignored.tentative.html
new file mode 100644
index 0000000..6d540f6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-radial-gradient-outside-subtree-ignored.tentative.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>drawElementImage does not use SVG resources from outside the subtree</title>
+  <script src='/resources/testharness.js'></script>
+  <script src='/resources/testharnessreport.js'></script>
+  <script src="/html/canvas/resources/wait-for-canvas-paint.js"></script>
+  <style>
+    a {
+      color: blue;
+    }
+    a:visited {
+      color: red;
+    }
+    canvas {
+      background-color: green;
+    }
+  </style>
+</head>
+<body>
+  <a href="">
+    <svg width="0" height="0">
+      <defs>
+        <radialGradient id="grad-outside">
+          <stop offset="0" stop-color="currentColor"/>
+          <stop offset="1" stop-color="currentColor"/>
+        </radialGradient>
+      </defs>
+    </svg>
+  </a>
+
+  <canvas id="canvas" width="100" height="100" layoutsubtree>
+    <div id="child">
+      <svg width="100" height="100">
+        <rect x="0" y="0" width="100" height="100" fill="url(#grad-outside)"/>
+      </svg>
+    </div>
+  </canvas>
+
+  <script>
+    window.onload = () => {
+      promise_test(async function(t) {
+        await waitForCanvasPaint(canvas);
+
+        var context = canvas.getContext("2d");
+
+        context.fillStyle = 'green';
+        context.fillRect(0, 0, 100, 100);
+
+        // Draw the element image
+        context.drawElementImage(child, 0, 0);
+
+        // The canvas should ignore the gradient and use transparent black.
+        let pixel = context.getImageData(50, 50, 1, 1).data;
+        assert_false(pixel[0] > 0, "The canvas should not use the gradient.");
+        assert_true(pixel[1] > 0, "The canvas should not use the gradient.");
+        assert_false(pixel[2] > 0, "The canvas should not use the gradient.");
+      });
+    };
+  </script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-color-ignored.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-color-ignored.tentative.html
deleted file mode 100644
index 5a149b2..0000000
--- a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-color-ignored.tentative.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>drawElementImage does not reveal visited link colors</title>
-  <script src='/resources/testharness.js'></script>
-  <script src='/resources/testharnessreport.js'></script>
-  <script src="/html/canvas/resources/wait-for-canvas-paint.js"></script>
-  <style>
-    #link {
-      width: 100px;
-      height: 100px;
-      background-color: green;
-      color: green;
-      display: block;
-    }
-    #link:visited {
-      background-color: red; /* Visited color */
-      color: red; /* Visited color */
-    }
-  </style>
-</head>
-<body>
-  <canvas id="canvas" width="100" height="100" layoutsubtree>
-    <a id="link" href="">link</a>
-  </canvas>
-
-  <script>
-    window.onload = () => {
-      promise_test(async function(t) {
-        await waitForCanvasPaint(canvas);
-
-        var context = canvas.getContext("2d");
-
-        // Draw the element image
-        context.drawElementImage(link, 0, 0);
-
-        // The canvas should NOT reflect the visited state (red), it should paint the unvisited state (green).
-        let pixel = context.getImageData(10, 10, 1, 1).data;
-        assert_false(pixel[0] > 0, "The canvas should not reflect the visited state.");
-        assert_true(pixel[1] > 0, "The canvas should not reflect the visited state.");
-      });
-    };
-  </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-currentcolor-ignored.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-currentcolor-ignored.tentative.html
deleted file mode 100644
index d4d94d1..0000000
--- a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-currentcolor-ignored.tentative.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>drawElementImage does not reveal visited link colors through currentColor</title>
-  <script src='/resources/testharness.js'></script>
-  <script src='/resources/testharnessreport.js'></script>
-  <script src="/html/canvas/resources/wait-for-canvas-paint.js"></script>
-  <style>
-    #link {
-      color: green;
-    }
-    #link:visited {
-      color: red;
-    }
-    #target {
-      width: 100px;
-      height: 100px;
-      background-color: currentColor;
-    }
-  </style>
-</head>
-<body>
-  <a id="link" href="">
-    <canvas id="canvas" width="100" height="100" layoutsubtree>
-      <div id="target"></div>
-    </canvas>
-  </a>
-
-  <script>
-    window.onload = () => {
-      promise_test(async function(t) {
-        await waitForCanvasPaint(canvas);
-
-        var context = canvas.getContext("2d");
-
-        // Draw the element image
-        context.drawElementImage(target, 0, 0);
-
-        // The canvas should NOT reflect the visited state (red), it should paint the unvisited state (green).
-        let pixel = context.getImageData(10, 10, 1, 1).data;
-        assert_false(pixel[0] > 0, "The canvas should not reflect the visited state.");
-        assert_true(pixel[1] > 0, "The canvas should not reflect the visited state.");
-      });
-    };
-  </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-decoration-color-ignored.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-decoration-color-ignored.tentative.html
deleted file mode 100644
index a215f0a..0000000
--- a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-decoration-color-ignored.tentative.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>drawElementImage does not reveal visited link colors</title>
-  <script src='/resources/testharness.js'></script>
-  <script src='/resources/testharnessreport.js'></script>
-  <script src="/html/canvas/resources/wait-for-canvas-paint.js"></script>
-  <style>
-    #link {
-      color: green;
-      text-decoration: underline 20px solid green;
-      width: 100px;
-      height: 100px;
-      display: block;
-    }
-    #link:visited {
-      color: red;
-      text-decoration: underline 20px solid red;
-    }
-  </style>
-</head>
-<body>
-  <canvas id="canvas" width="100" height="100" layoutsubtree>
-    <a id="link" href="">link</a>
-  </canvas>
-
-  <script>
-    window.onload = () => {
-      promise_test(async function(t) {
-        await waitForCanvasPaint(canvas);
-
-        var context = canvas.getContext("2d");
-
-        // Draw the element image
-        context.drawElementImage(link, 0, 0);
-
-        // The canvas should NOT reflect the visited state (red), it should paint the unvisited state (green).
-        let pixel = context.getImageData(20, 40, 1, 1).data;
-        assert_false(pixel[0] > 0, "The canvas should not reflect the visited state.");
-        assert_true(pixel[1] > 0, "The canvas should not reflect the visited state.");
-      });
-    };
-  </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-svg-fill-stroke-color-ignored.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-svg-fill-stroke-color-ignored.tentative.html
deleted file mode 100644
index b56e9876..0000000
--- a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-svg-fill-stroke-color-ignored.tentative.html
+++ /dev/null
@@ -1,46 +0,0 @@
-<!DOCTYPE HTML>
... (file diff truncated)
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-linear-gradient-outside-subtree-ignored.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-linear-gradient-outside-subtree-ignored.tentative.html
new file mode 100644
index 0000000..da2ee27
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-linear-gradient-outside-subtree-ignored.tentative.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>drawElementImage does not use SVG resources from outside the subtree</title>
+  <script src='/resources/testharness.js'></script>
+  <script src='/resources/testharnessreport.js'></script>
+  <script src="/html/canvas/resources/wait-for-canvas-paint.js"></script>
+  <style>
+    a {
+      color: blue;
+    }
+    a:visited {
+      color: red;
+    }
+    canvas {
+      background-color: green;
+    }
+  </style>
+</head>
+<body>
+  <a href="">
+    <svg width="0" height="0">
+      <defs>
+        <linearGradient id="grad-outside">
+          <stop offset="0" stop-color="currentColor"/>
+          <stop offset="1" stop-color="currentColor"/>
+        </linearGradient>
+      </defs>
+    </svg>
+  </a>
+
+  <canvas id="canvas" width="100" height="100" layoutsubtree>
+    <div id="child">
+      <svg width="100" height="100">
+        <rect x="0" y="0" width="100" height="100" fill="url(#grad-outside)"/>
+      </svg>
+    </div>
+  </canvas>
+
+  <script>
+    window.onload = () => {
+      promise_test(async function(t) {
+        await waitForCanvasPaint(canvas);
+
+        var context = canvas.getContext("2d");
+
+        context.fillStyle = 'green';
+        context.fillRect(0, 0, 100, 100);
+
+        // Draw the element image
+        context.drawElementImage(child, 0, 0);
+
+        // The canvas should ignore the gradient and use transparent black.
+        let pixel = context.getImageData(50, 50, 1, 1).data;
+        assert_false(pixel[0] > 0, "The canvas should not use the gradient.");
+        assert_true(pixel[1] > 0, "The canvas should not use the gradient.");
+        assert_false(pixel[2] > 0, "The canvas should not use the gradient.");
+      });
+    };
+  </script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-pattern-outside-subtree-ignored.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-pattern-outside-subtree-ignored.tentative.html
new file mode 100644
index 0000000..71ab5f6d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-pattern-outside-subtree-ignored.tentative.html
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>drawElementImage does not use SVG patterns outside the subtree</title>
+  <link rel="help" href="https://github.com/WICG/html-in-canvas">
+  <script src='/resources/testharness.js'></script>
+  <script src='/resources/testharnessreport.js'></script>
+  <script src="/html/canvas/resources/wait-for-canvas-paint.js"></script>
+</head>
+<body>
+  <svg width="0" height="0">
+    <defs>
+      <pattern id="pattern" patternUnits="userSpaceOnUse" viewBox="0 0 100 100" width="100" height="100">
+        <image href="/images/red-100x100.png" x="0" y="0" width="100" height="100" preserveAspectRatio="none"/>
+      </pattern>
+    </defs>
+  </svg>
+
+  <canvas id="canvas" width="100" height="100" layoutsubtree>
+    <svg id=child width="100" height="100">
+      <rect x="0" y="0" width="100" height="100" fill="url(#pattern)"/>
+    </svg>
+  </canvas>
+
+  <script>
+    window.onload = () => {
+      promise_test(async function(t) {
+        const preloadImage = (url) => new Promise((resolve, reject) => {
+          const img = new Image();
+          img.onload = () => resolve(img);
+          img.onerror = () => reject(new Error(`Failed to load image: ${url}`));
+          img.src = url;
+        });
+
+        const imageEl = document.querySelector('#pattern image');
+        await Promise.all([
+          preloadImage(imageEl.getAttribute('href')),
+        ]);
+
+        await waitForCanvasPaint(canvas);
+        var ctx = canvas.getContext('2d');
+        ctx.fillStyle = 'green';
+        ctx.fillRect(0, 0, 100, 100);
+        ctx.drawElementImage(child, 0, 0);
+
+        // The canvas should ignore the gradient and use transparent black.
+        let pixel = ctx.getImageData(50, 50, 1, 1).data;
+        assert_false(pixel[0] > 0, "The canvas should not use the pattern.");
+        assert_true(pixel[1] > 0, "The canvas should not use the pattern.");
+        assert_false(pixel[2] > 0, "The canvas should not use the pattern.");
+      });
+    }
+  </script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-radial-gradient-outside-subtree-ignored.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-radial-gradient-outside-subtree-ignored.tentative.html
new file mode 100644
index 0000000..6d540f6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/svg-radial-gradient-outside-subtree-ignored.tentative.html
@@ -0,0 +1,62 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>drawElementImage does not use SVG resources from outside the subtree</title>
+  <script src='/resources/testharness.js'></script>
+  <script src='/resources/testharnessreport.js'></script>
+  <script src="/html/canvas/resources/wait-for-canvas-paint.js"></script>
+  <style>
+    a {
+      color: blue;
+    }
+    a:visited {
+      color: red;
+    }
+    canvas {
+      background-color: green;
+    }
+  </style>
+</head>
+<body>
+  <a href="">
+    <svg width="0" height="0">
+      <defs>
+        <radialGradient id="grad-outside">
+          <stop offset="0" stop-color="currentColor"/>
+          <stop offset="1" stop-color="currentColor"/>
+        </radialGradient>
+      </defs>
+    </svg>
+  </a>
+
+  <canvas id="canvas" width="100" height="100" layoutsubtree>
+    <div id="child">
+      <svg width="100" height="100">
+        <rect x="0" y="0" width="100" height="100" fill="url(#grad-outside)"/>
+      </svg>
+    </div>
+  </canvas>
+
+  <script>
+    window.onload = () => {
+      promise_test(async function(t) {
+        await waitForCanvasPaint(canvas);
+
+        var context = canvas.getContext("2d");
+
+        context.fillStyle = 'green';
+        context.fillRect(0, 0, 100, 100);
+
+        // Draw the element image
+        context.drawElementImage(child, 0, 0);
+
+        // The canvas should ignore the gradient and use transparent black.
+        let pixel = context.getImageData(50, 50, 1, 1).data;
+        assert_false(pixel[0] > 0, "The canvas should not use the gradient.");
+        assert_true(pixel[1] > 0, "The canvas should not use the gradient.");
+        assert_false(pixel[2] > 0, "The canvas should not use the gradient.");
+      });
+    };
+  </script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-color-ignored.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-color-ignored.tentative.html
deleted file mode 100644
index 5a149b2..0000000
--- a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-color-ignored.tentative.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>drawElementImage does not reveal visited link colors</title>
-  <script src='/resources/testharness.js'></script>
-  <script src='/resources/testharnessreport.js'></script>
-  <script src="/html/canvas/resources/wait-for-canvas-paint.js"></script>
-  <style>
-    #link {
-      width: 100px;
-      height: 100px;
-      background-color: green;
-      color: green;
-      display: block;
-    }
-    #link:visited {
-      background-color: red; /* Visited color */
-      color: red; /* Visited color */
-    }
-  </style>
-</head>
-<body>
-  <canvas id="canvas" width="100" height="100" layoutsubtree>
-    <a id="link" href="">link</a>
-  </canvas>
-
-  <script>
-    window.onload = () => {
-      promise_test(async function(t) {
-        await waitForCanvasPaint(canvas);
-
-        var context = canvas.getContext("2d");
-
-        // Draw the element image
-        context.drawElementImage(link, 0, 0);
-
-        // The canvas should NOT reflect the visited state (red), it should paint the unvisited state (green).
-        let pixel = context.getImageData(10, 10, 1, 1).data;
-        assert_false(pixel[0] > 0, "The canvas should not reflect the visited state.");
-        assert_true(pixel[1] > 0, "The canvas should not reflect the visited state.");
-      });
-    };
-  </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-currentcolor-ignored.tentative.html b/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-currentcolor-ignored.tentative.html
deleted file mode 100644
index d4d94d1..0000000
--- a/third_party/blink/web_tests/external/wpt/html/canvas/element/manual/draw-element-image/privacy/visited-link-currentcolor-ignored.tentative.html
+++ /dev/null
@@ -1,47 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>drawElementImage does not reveal visited link colors through currentColor</title>
-  <script src='/resources/testharness.js'></script>
-  <script src='/resources/testharnessreport.js'></script>
-  <script src="/html/canvas/resources/wait-for-canvas-paint.js"></script>
-  <style>
-    #link {
-      color: green;
-    }
-    #link:visited {
-      color: red;
-    }
-    #target {
-      width: 100px;
-      height: 100px;
-      background-color: currentColor;
-    }
-  </style>
-</head>
-<body>
-  <a id="link" href="">
-    <canvas id="canvas" width="100" height="100" layoutsubtree>
-      <div id="target"></div>
-    </canvas>
-  </a>
-
-  <script>
-    window.onload = () => {
-      promise_test(async function(t) {
-        await waitForCanvasPaint(canvas);
-
-        var context = canvas.getContext("2d");
-
-        // Draw the element image
-        context.drawElementImage(target, 0, 0);
-
-        // The canvas should NOT reflect the visited state (red), it should paint the unvisited state (green).
-        let pixel = context.getImageData(10, 10, 1, 1).data;
-        assert_false(pixel[0] > 0, "The canvas should not reflect the visited state.");
-        assert_true(pixel[1] > 0, "The canvas should not reflect the visited state.");
-      });
-    };
-  </script>
-</body>
... (truncated)
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.