Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in SVG
DescriptionUse after free in SVG
ComponentSVG
Sub-componentBlink>SVG
Bug ClassUAF
Tracker565742179
Fix commitdedbd3f9dee8 (chromium/src) +8/-4
CISA KEVNot listed
Creditedxinyang
Disclosed2026-10-01

Changed Functions

FunctionChangeNotes
if
third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
modified

Files Changed

  • third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
From dedbd3f9dee8a579418b56c9a37c643873aafe1c Mon Sep 17 00:00:00 2001
From: Stefan Zager <szager@chromium.org>
Date: Mon, 28 Sep 2026 17:24:58 -0700
Subject: [PATCH] Reinsert PatternData into pattern map after reconstruction

LayoutSVGResourcePattern::pattern_map_ can be cleared while executing
BuildPatternData, so be sure it reinsert the newly-created pattern
data rather than using the (possibly stale) previous hash table
AddResult.

Fixed: 565742179
Change-Id: Iad113e3101920adf4b56da4805b4a46ebf681730
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8464440
Reviewed-by: Fredrik Söderquist <fs@opera.com>
Commit-Queue: Stefan Zager <szager@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1706535}
---
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
index a482c01..86b0498 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
@@ -192,14 +192,18 @@
   NOT_DESTROYED();
   ClearInvalidationMask();
 
-  std::unique_ptr<PatternData>& pattern_data =
-      pattern_map_.insert(&client, nullptr).stored_value->value;
+  auto iter = pattern_map_.find(&client);
+  PatternData* pattern_data =
+      (iter == pattern_map_.end() ? nullptr : iter->value.get());
   if (pattern_data && pattern_data->paint_flags != paint_flags) {
-    pattern_data.reset();
+    pattern_data = nullptr;
   }
 
   if (!pattern_data) {
-    pattern_data = BuildPatternData(reference_box, paint_flags);
+    auto new_pattern_data = BuildPatternData(reference_box, paint_flags);
+    pattern_data = new_pattern_data.get();
+    CHECK(pattern_data);
+    pattern_map_.Set(&client, std::move(new_pattern_data));
     pattern_data->paint_flags = paint_flags;
   }
 
Loading diff…

Original Bug Report

reported by xi...@anthropic.com

Use-after-free in blink::LayoutSVGResourcePattern::ApplyShader

Summary

LayoutSVGResourcePattern::ApplyShader() holds a reference into pattern_map_’s backing store while BuildPatternData() paints the pattern’s content. A CSS Paint Worklet paint() callback that runs on the main thread during that paint can call registerPaint(), which synchronously invalidates the pattern and frees the backing. ApplyShader() then uses the stale reference. Renderer process, zero interaction.

Environment

  • Chrome for Testing 154.0.8037.57 (Stable), 155.0.8059.12 (Beta), 156.0.8072.0 (Canary); code unchanged on main b7c07f35773a
  • Ubuntu 24.04, x86-64
  • Evidence build: ASan, Chromium 155.0.8038.0

Reproduction

chrome --user-data-dir=/tmp/p --no-first-run poc.html
  1. Launch with a fresh profile.
  2. Wait; zero interaction beyond loading the page. The renderer crashes after about 3 s.

Rate: Stable 4/4, Beta 3/3, Canary 4/4.

Evidence

Renderer, main thread. Full reports: asan.txt, asan-dcheck.txt (DCHECK build, same bug, no DCHECK fires).

use-after-poison READ of size 8
  #0 LayoutSVGResourcePattern::ApplyShader
  #1 SVGObjectPainter::PreparePaint  svg_object_painter.cc:41
freed (Oilpan):  LayoutSVGResourcePattern::RemoveAllClientsFromCache
  <- LayoutSVGImage::ImageChanged <- CSSPaintValue::Observer::PaintImageGeneratorReady
  <- PaintWorklet::RegisterCSSPaintDefinition <- PaintWorkletGlobalScope::registerPaint

Vulnerable code

third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc

 64   pattern_map_.clear();                                            [3]
195   std::unique_ptr<PatternData>& pattern_data =
196       pattern_map_.insert(&client, nullptr).stored_value->value;   [1]
202   pattern_data = BuildPatternData(reference_box, paint_flags);     [2]

[1] Reference into the HeapHashMap backing. [2] Paints the pattern’s children, then assigns through that reference. If a child’s paint reaches [3], the backing is freed while [1] is live.

Impact

Any web page in a secure context, no interaction. Renderer use-after-free. Reporter’s estimate: High (S1).

Discovery and validation

Found by AI-assisted source review and dynamic testing (Claude).

Attachments: poc.html, asan.txt, asan-dcheck.txt, report.md (full write-up)

View on issue tracker