Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactImproper input validation in ReaderMode
DescriptionImproper input validation in ReaderMode
ComponentReaderMode
Bug ClassLogic Error
Tracker523237735
Fix commit558ee3257125 (chromium/src) +33/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-08-25

Changed Functions

FunctionChangeNotes
if
components/dom_distiller/core/javascript/content_processing.js
modified
suite
components/test/data/dom_distiller/content_processing_tester.js
modified

Files Changed

  • components/dom_distiller/core/javascript/content_processing.js
  • components/test/data/dom_distiller/content_processing_tester.js
From 558ee3257125495bfbfefb1bc5cbd16602861ea8 Mon Sep 17 00:00:00 2001
From: Quentin Pubert <qpubert@google.com>
Date: Mon, 06 Jul 2026 08:28:57 -0700
Subject: [PATCH] [Reader Mode] Fix sanitizeLinks() bypass via SVG <a> with xlink:href

In components/dom_distiller/core/javascript/content_processing.js,
sanitizeLinks() previously checked only
linkElement.getAttribute('href'). For SVG <a> elements using xlink:href,
getAttribute('href') returns null, causing sanitizeLinks() to skip
sanitizing the element.

This change updates sanitizeLinks() to also check for the namespaced
xlink:href attribute via getAttributeNS('http://www.w3.org/1999/xlink',
'href'). Also adds regression unit tests to
content_processing_tester.js.

Fixed: 523237735
Change-Id: I1c03459b6fd7a38910c002f88267189149168fd5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8025111
Reviewed-by: Olivier Robin <olivierrobin@chromium.org>
Commit-Queue: Matthew Jones <mdjones@chromium.org>
Reviewed-by: Matthew Jones <mdjones@chromium.org>
Auto-Submit: Quentin Pubert <qpubert@google.com>
Cr-Commit-Position: refs/heads/main@{#1657211}
---

diff --git a/components/dom_distiller/core/javascript/content_processing.js b/components/dom_distiller/core/javascript/content_processing.js
index 2445f16..1b521108 100644
--- a/components/dom_distiller/core/javascript/content_processing.js
+++ b/components/dom_distiller/core/javascript/content_processing.js
@@ -11,7 +11,8 @@
   const allLinks = element.querySelectorAll('a');
 
   allLinks.forEach(linkElement => {
-    const href = linkElement.getAttribute('href');
+    const href = linkElement.getAttribute('href') ||
+        linkElement.getAttributeNS('http://www.w3.org/1999/xlink', 'href');
 
     if (href) {
       let keepLink = false;
diff --git a/components/test/data/dom_distiller/content_processing_tester.js b/components/test/data/dom_distiller/content_processing_tester.js
index 519d5a5..e6ddc5e 100644
--- a/components/test/data/dom_distiller/content_processing_tester.js
+++ b/components/test/data/dom_distiller/content_processing_tester.js
@@ -82,6 +82,37 @@
     assert.equal(links.length, 0);
     assert.equal(testContainer.innerHTML, 'Mailto Link');
   });
+
+  test(
+      'sanitizeLinks should remove javascript SVG links with xlink:href',
+      async function() {
+        const {assert} = await import('./index.js');
+        testContainer.innerHTML = '<svg><a xlink:href="javascript:void(0)">' +
+            '<text>SVG JS Link</text></a></svg>';
+        sanitizeLinks(testContainer);
+        const links = testContainer.querySelectorAll('a');
+        assert.equal(links.length, 0);
+        assert.equal(
+            testContainer.querySelector('svg').innerHTML,
+            '<text>SVG JS Link</text>');
+      });
+
+  test(
+      'sanitizeLinks should keep valid http/https SVG links with xlink:href ' +
+          'and open in new tab',
+      async function() {
+        const {assert} = await import('./index.js');
+        testContainer.innerHTML =
+            '<svg><a xlink:href="https://example.com">' +
+            '<text>SVG HTTPS Link</text></a></svg>';
+        sanitizeLinks(testContainer);
+        const links = testContainer.querySelectorAll('a');
+        assert.equal(links.length, 1);
+        assert.equal(
+            links[0].getAttributeNS('http://www.w3.org/1999/xlink', 'href'),
+            'https://example.com');
+        assert.equal(links[0].target, '_blank');
+      });
 });
 
 suite('ContentProcessing.removeExtraneousElementsFrom', function() {
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/components/test/data/dom_distiller/content_processing_tester.js b/components/test/data/dom_distiller/content_processing_tester.js
index 519d5a5..e6ddc5e 100644
--- a/components/test/data/dom_distiller/content_processing_tester.js
+++ b/components/test/data/dom_distiller/content_processing_tester.js
@@ -82,6 +82,37 @@
     assert.equal(links.length, 0);
     assert.equal(testContainer.innerHTML, 'Mailto Link');
   });
+
+  test(
+      'sanitizeLinks should remove javascript SVG links with xlink:href',
+      async function() {
+        const {assert} = await import('./index.js');
+        testContainer.innerHTML = '<svg><a xlink:href="javascript:void(0)">' +
+            '<text>SVG JS Link</text></a></svg>';
+        sanitizeLinks(testContainer);
+        const links = testContainer.querySelectorAll('a');
+        assert.equal(links.length, 0);
+        assert.equal(
+            testContainer.querySelector('svg').innerHTML,
+            '<text>SVG JS Link</text>');
+      });
+
+  test(
+      'sanitizeLinks should keep valid http/https SVG links with xlink:href ' +
+          'and open in new tab',
+      async function() {
+        const {assert} = await import('./index.js');
+        testContainer.innerHTML =
+            '<svg><a xlink:href="https://example.com">' +
+            '<text>SVG HTTPS Link</text></a></svg>';
+        sanitizeLinks(testContainer);
+        const links = testContainer.querySelectorAll('a');
+        assert.equal(links.length, 1);
+        assert.equal(
+            links[0].getAttributeNS('http://www.w3.org/1999/xlink', 'href'),
+            'https://example.com');
+        assert.equal(links[0].target, '_blank');
+      });
 });
 
 suite('ContentProcessing.removeExtraneousElementsFrom', function() {
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.