Chrome · ReaderMode
CVE-2026-78980
Logic Error in ReaderMode
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifcomponents/dom_distiller/core/javascript/content_processing.js |
modified | |
suitecomponents/test/data/dom_distiller/content_processing_tester.js |
modified |
Files Changed
components/dom_distiller/core/javascript/content_processing.jscomponents/test/data/dom_distiller/content_processing_tester.js
Patch
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.
References
On This Page