CVE-2026-118308
Overview
Background
- SVG SMIL animation
<animate>,<set>,<animateTransform>, etc. are “timed elements” that schedule themselves on an SVG time container (the document timeline) to drive animations.- `SVGSMILElement`
- the Blink base class (
third_party/blink/renderer/core/svg/animation/svg_smil_element.cc) for these timed elements; it manages scheduling, target-element resolution, and event/condition references. It is an OilpanGarbageCollectedobject referenced viaMember<>/raw references from the time container. - `<use>` shadow tree
<svg:use>instantiates a referenced subtree as a shadow (instance) tree. Instance-tree nodes are clones and are not supposed to participate independently in document machinery such as the animation timeline.- `InUseShadowTree()`
- predicate that is true when the element lives inside a
<use>-generated shadow tree. - The modified method
- the removal/disconnection path that runs
ClearResourceAndEventBaseReferences()andDisconnectConditions(), then decides, viaisConnected(), whether to detach the element from the timeline and clear its target.
Root Cause Analysis
When a timed element is removed/disconnected, the method clears its resource and event-base references and disconnects its conditions, then checks if (!isConnected()) to decide whether to also reset the target element and bail out (i.e., stop participating in the timeline). The invariant the code assumed was: a timed element is either genuinely connected to the document (and should be scheduled) or not connected (and should be treated as absent). That missed a third state — a timed element that has been inserted into a <use> shadow tree. The commit notes this is “currently possible via a cloned event handler”: a cloned handler path can land a live SVGSMILElement inside a <use> instance tree where isConnected() is true, so the old code left it scheduled on the timeline and keeping a target element. Instance-tree nodes have a distinct, controller-managed lifetime; a timed element still registered with the time container (or still holding a target reference) after its instance subtree is rebuilt/destroyed leaves the timeline holding a dangling reference to a freed Oilpan object — the use-after-free the advisory reports.
The one-line fix changes the guard to if (!isConnected() || InUseShadowTree()), so an element in a <use> shadow tree takes the same path as a disconnected one: SetTargetElement(nullptr) and early return, making it inert on the timeline exactly as the commit title says (“Make timed elements inserted into <use> shadow trees inert”). Because these are Oilpan GarbageCollected objects, the specific freed object and the dangling edge (time-container scheduling list vs. target Member) are not shown by this diff and are (inferred) from the advisory’s UAF label and the fix’s intent; what the diff proves is that an in-<use>-shadow timed element was wrongly kept active.
<use> shadow tree (via a cloned event handler) stayed scheduled on the timeline, leaving a dangling reference once its instance tree was torn down.Attack Path
- Craft SVG
Attacker builds an SVG with a
<use>referencing a subtree and an event handler that, when cloned into the instance tree, carries/creates a SMIL timed element. (cloned-event-handler mechanism per commit) - Insertion into instance tree
The clone path places the live
SVGSMILElementinside the<use>shadow tree whereisConnected()is true. (inferred specifics) - Stays scheduled
Because the old guard only checked
isConnected(), the element remains registered on the time container and retains a target element. - Instance teardown
The
<use>instance tree is rebuilt or removed, freeing the instance nodes while the timeline still references the timed element. (freed-memory inferred) - Primitive The timeline dereferences the dangling timed element during scheduling, a renderer use-after-free. (escalation inferred)
Impact Assessment
<use> and animation elements; no special privilege. The advisory’s UAF classification is consistent with the fix (making an improperly-scheduled instance-tree element inert). The diff substantiates the logic gap (missing InUseShadowTree() case) directly; the freed object, the exact dangling pointer, and any escalation to RCE are (inferred) since the one-line guard does not expose the sink. If the inferred dangling-timeline-reference is as described, this is a strong, remotely-triggerable UAF; at minimum the diff proves a lifetime/scheduling invariant was violated.Files Changed
third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
Audit Directions
- `isConnected()`-only lifetime checks in SVGSearch
core/svgfor places that gate scheduling/registration solely onisConnected()without excluding<use>instance trees; the same third-state gap may exist elsewhere (e.g., resource references, event bases). - `<use>` instance-tree participationReview which node types can end up inside a
<use>shadow tree via cloned handlers/attributes and whether any register with document-level managers (timeline, resources, observers). - Time-container registration/unregistrationVerify every path that adds a timed element to the time container has a matching removal when the element becomes inert, including instance-tree rebuilds.
Patch
From 270d5d328addf47356621fb27f93873d5cd5e96f Mon Sep 17 00:00:00 2001 From: Fredrik Söderquist <[email protected]> Date: Mon, 19 Oct 2026 13:53:59 -0700 Subject: [PATCH] Make timed elements inserted into <use> shadow trees inert If timed elements somehow make it into a <use> shadow tree, they should not be scheduled on the timeline. Treat them the same as if they were not in the document at all. Fixed: 574791952 Change-Id: I0a88c3a352139fbe2b93f4634794de929826ff47 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8610829 Reviewed-by: Stephen Chenney <[email protected]> Commit-Queue: Stephen Chenney <[email protected]> Auto-Submit: Fredrik Söderquist <[email protected]> Cr-Commit-Position: refs/heads/main@{#1722305} --- diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc index f64f6064..fe85e6a 100644 --- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc +++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc @@ -328,7 +328,9 @@ ClearResourceAndEventBaseReferences(); DisconnectConditions(); - if (!isConnected()) { + // Ignore timed elements that are inserted into a <use> shadow tree. This is + // currently possible via a cloned event handler. + if (!isConnected() || InUseShadowTree()) { // Reset the target element if we are no longer in the document. SetTargetElement(nullptr); return;