High patch-now ✔︎ verified CVSS 8.8 chrome UAF 📄 Reporter bug report 🔧 Commit mapped

Overview

High
Severity
8.8
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in SVG
DescriptionUse after free in SVG
ComponentSVG
Sub-componentBlink>SVG
Bug ClassUAF
Action tierpatch-now — corruption primitive, web-reachable in default config (confirmed) — factors set by independent review by AI
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Independent review by AIConfirmed
A second, independent AI reviewer (not a human) re-derived this analysis from the fixing commit and the vendor advisory, looking for errors.
Additionally cross-checked: a second, different model independently derived the same bug class, vulnerable function and fix from the commit.
Tracker513754619
Fix commitca1a93a88114 (chromium/src) +11/-5
CWECWE-416 (Use-after-free)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CISA KEVNot listed
CreditedGoogle
Reported2026-05-16 (per vendor advisory)
Fix landed2026-05-19 (public git)
Disclosed2026-05-27
Patch gap8 days — fix public in source before the advisory

Background

`SVGTreeScopeResources`
a Blink object holding a tree scope’s SVG resources in a resources_ map keyed by id (svg_tree_scope_resources.cc:12-15).
`ResourceForId`
looks up (or lazily creates) the LocalSVGResource for a given id (svg_tree_scope_resources.cc:17-24).
`ProcessCustomWeakness`
an Oilpan weak callback that unregisters dead resources and calls resources_.RemoveAll(to_remove) during GC (svg_tree_scope_resources.cc:36-46).
Oilpan safepoint
allocating a garbage-collected object can synchronously run a GC cycle, including weak callbacks.

Root Cause Analysis

Pre-fix, ResourceForId binds a C++ reference directly into the map’s backing store with auto& entry = resources_.insert(id, nullptr).stored_value->value (svg_tree_scope_resources.cc:20). It then lazily constructs the resource via entry = MakeGarbageCollected<LocalSVGResource>(*tree_scope_, id) (:22) and finally returns entry.Get() (:23). The invariant this relies on is that entry stays valid across the allocation, but MakeGarbageCollected can trigger a synchronous GC whose weak processing runs SVGTreeScopeResources::ProcessCustomWeakness, which removes dead entries with resources_.RemoveAll(to_remove) (:45). Because resources_ is a WTF::HashMap (not a HeapHashMap), that removal can shrink and reallocate the backing store during GC (per the commit message and reporter), freeing the storage that entry references; the subsequent assignment and entry.Get() then write and read freed memory.

The fix removes the held reference: it does an explicit auto it = resources_.find(id) and returns the existing value if present, otherwise constructs the resource into a local auto* new_entry, inserts it with resources_.Set(id, new_entry), and returns the local (svg_tree_scope_resources.cc diff). Since the allocation result is held in a local rather than a reference into the backing store, a GC-driven shrink during MakeGarbageCollected can no longer leave a dangling reference.

Key insight
The code held a reference into a HashMap backing store across a GC-triggering allocation that could shrink and reallocate that store; splitting insert() into find() plus a post-allocation Set() keeps no reference across the safepoint.

Attack Path

  1. Grow the resource map A page creates many SVG resource references so resources_ grows (svg_tree_scope_resources.cc:20). (inferred per reporter)
  2. Make entries collectible Most referenced resources are removed from the DOM so they become eligible for GC. (inferred)
  3. Force a sync GC on insert A call to ResourceForId with a new id reaches MakeGarbageCollected (:22), which triggers a synchronous GC whose ProcessCustomWeakness shrinks the map (:45). (inferred that the allocation triggers GC)
  4. Use freed storage Execution resumes and writes/reads through the now-dangling entry reference into freed backing store (:22-23).

Impact Assessment

An attacker-controlled page could cause a write and read of freed PartitionAlloc memory in the renderer process by driving a synchronous GC during SVG resource lookup. The advisory rates this a high-severity use-after-free with no in-the-wild exploitation. Escalation to memory corruption or code execution is (inferred); the shown code demonstrates the dangling-reference access.

Files Changed

  • third_party/blink/renderer/core/svg/svg_tree_scope_resources.cc

Audit Directions

  • References into container backing stores
    Flag any auto&/pointer bound to a HashMap/Vector slot that is used after a call which may allocate or trigger GC.
  • Allocation across GC safepoints
    Treat MakeGarbageCollected (and anything that can allocate on the Oilpan heap) as a point where weak callbacks may mutate containers.
  • Non-heap maps touched by weak callbacks
    Audit WTF::HashMap members (vs HeapHashMap) that are modified from GC weak-processing, since they can shrink/reallocate mid-GC.
From ca1a93a881145b48592541b57fc2c630970a9970 Mon Sep 17 00:00:00 2001
From: Fredrik Söderquist <fs@opera.com>
Date: Tue, 19 May 2026 09:37:47 -0700
Subject: [PATCH] Avoid shrinking the map via sync GC in SVGTreeScopeResources

Because `resources_` is a HashMap, the allocation of the new entry
can trigger GC and thus shrink the map's backing store.

Split the insert() into find()+Set() to avoid this.

Fixed: 513754619
Change-Id: I8c10cec062423bb616e2443339864fc202c78a55
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7855154
Auto-Submit: Fredrik Söderquist <fs@opera.com>
Commit-Queue: Philip Rogers <pdr@chromium.org>
Reviewed-by: Philip Rogers <pdr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1632930}
---

diff --git a/third_party/blink/renderer/core/svg/svg_tree_scope_resources.cc b/third_party/blink/renderer/core/svg/svg_tree_scope_resources.cc
index 2d2ab9b48..8cb2207 100644
--- a/third_party/blink/renderer/core/svg/svg_tree_scope_resources.cc
+++ b/third_party/blink/renderer/core/svg/svg_tree_scope_resources.cc
@@ -15,12 +15,18 @@
     : tree_scope_(tree_scope) {}
 
 LocalSVGResource* SVGTreeScopeResources::ResourceForId(const AtomicString& id) {
-  if (id.empty())
+  if (id.empty()) {
     return nullptr;
-  auto& entry = resources_.insert(id, nullptr).stored_value->value;
-  if (!entry)
-    entry = MakeGarbageCollected<LocalSVGResource>(*tree_scope_, id);
-  return entry.Get();
+  }
+  auto it = resources_.find(id);
+  if (it != resources_.end()) {
+    return it->value;
+  }
+  // Use explicit Set() (rather than insert()) to avoid garbage collection
+  // shrinking the `resources_` map.
+  auto* new_entry = MakeGarbageCollected<LocalSVGResource>(*tree_scope_, id);
+  resources_.Set(id, new_entry);
+  return new_entry;
 }
 
 LocalSVGResource* SVGTreeScopeResources::ExistingResourceForId(
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential Use-After-Free in SVGTreeScopeResources::ResourceForId

Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: A potential Use-After-Free (UAF) exists in SVGTreeScopeResources::ResourceForId because a C++ reference to a map entry is held across a garbage collection safepoint. If a synchronous GC triggers a map shrink during this safepoint, the reference becomes dangling, leading to a write and read of freed memory.

Affected files:

  • third_party/blink/renderer/core/svg/svg_tree_scope_resources.cc
  • third_party/blink/renderer/core/svg/svg_tree_scope_resources.h

Estimated timestamp from git blame: Unknown (Google3 checkout)

Summary

A potential Use-After-Free vulnerability has been identified in SVGTreeScopeResources::ResourceForId. The issue arises from maintaining a C++ reference to an element within a WTF::HashMap across an Oilpan garbage collection (GC) safepoint. In certain conditions, the map’s backing store can be reallocated and freed during the GC, leaving the reference dangling.

Vulnerability Details

In third_party/blink/renderer/core/svg/svg_tree_scope_resources.cc, the ResourceForId method is implemented as follows:

LocalSVGResource* SVGTreeScopeResources::ResourceForId(const AtomicString& id) {
  if (id.empty())
    return nullptr;
  auto& entry = resources_.insert(id, nullptr).stored_value->value;   // (1) Reference to backing store
  if (!entry)
    entry = MakeGarbageCollected<LocalSVGResource>(*tree_scope_, id); // (2) Potential synchronous GC
  return entry.Get();                                                 // (3) Use of potentially dangling reference
}
  1. At (1), entry is a C++ reference (UntracedMember<LocalSVGResource>&) pointing to a location inside the resources_ map’s backing store. The resources_ map is a HashMap using the default PartitionAllocator.
  2. At (2), MakeGarbageCollected can trigger a synchronous Oilpan garbage collection. During this GC, SVGTreeScopeResources::ProcessCustomWeakness is executed as a weak callback.
  3. ProcessCustomWeakness removes dead entries from resources_ via RemoveAll. In a standard HashMap using PartitionAllocator, the ShouldShrink() check during deletion calls PartitionAllocator::IsAllocationAllowed(), which always returns true. This allows the map to perform a Shrink() operation during the GC weak processing phase.
  4. Shrink() allocates a new backing store and immediately deallocates the old one. This causes the entry reference in ResourceForId to become dangling.
  5. At (3), the code resumes and writes the new resource pointer into the freed memory, then reads it back to return it.

Unlike HeapHashMap (which uses HeapAllocator), the use of PartitionAllocator in this context does not suppress shrinking during GC, creating the window for the UAF.

Potential Attack Scenario

While our analysis is based on code review and we have not yet developed a functional proof of concept, we suggest an attacker might follow these steps to trigger the vulnerability:

  1. Use a web page to create a large number of SVG resource references (e.g., via clip-path: url(#id)), causing SVGTreeScopeResources::resources_ to grow.
  2. Remove most of those resources from the DOM, making them eligible for garbage collection.
  3. Trigger a call to ResourceForId with a new ID. If this call triggers a synchronous GC (e.g., by ensuring the Oilpan heap is near its limit), the ProcessCustomWeakness callback will shrink the map.
  4. The subsequent write/read in ResourceForId will occur on freed PartitionAlloc memory. If this memory is reclaimed by other allocations during the GC finalization, memory corruption or remote code execution may be possible.

Suggested Fix

Avoid holding a reference to the map entry across the MakeGarbageCollected call. Instead, perform the insertion and then update the map after the allocation is complete, or store the result of insert in a temporary variable that is not a reference into the backing store.

LocalSVGResource* SVGTreeScopeResources::ResourceForId(const AtomicString& id) {
  if (id.empty())
    return nullptr;
  auto it = resources_.find(id);
  if (it != resources_.end() && it->value)
    return it->value.Get();

  auto* resource = MakeGarbageCollected<LocalSVGResource>(*tree_scope_, id);
  resources_.Set(id, resource);
  return resource;
}

Evaluated with Chrome root at commit: 1a8d40fc44df2088d5945c0bf53584038aa1614a


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.

View on issue tracker