From 4321c21a5346235446bd2142eef6949ad67e4182 Mon Sep 17 00:00:00 2001 From: arturovt Date: Sat, 23 May 2026 23:16:02 +0300 Subject: [PATCH] fix(zone.js): validate __Zone_symbol_prefix to prevent DOM clobbering attacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, `__Zone_symbol_prefix` was read directly from `globalThis` without validating its type: const symbolPrefix = global['__Zone_symbol_prefix'] || '__zone_symbol__'; This made it possible for DOM clobbering to interfere with Zone’s internal symbol handling. If an attacker injected a DOM element with the same name (for example via a form field or anchor ID), `global['__Zone_symbol_prefix']` could resolve to a DOM element instead of a string. Because DOM elements are truthy, the fallback would not be used, and Zone would construct invalid internal keys (e.g. “[object HTMLFormElement]...”), breaking patching and lookup logic in subtle ways. After the fix, `rawPrefix` is only accepted when it is a string matching `/^[a-zA-Z0-9_]+$/`. Any other value (DOM nodes, empty strings, or strings with unexpected characters) is rejected and replaced with the default `'__zone_symbol__'`. This prevents DOM clobbering from influencing Zone’s internal symbol generation and keeps the patching system stable even in the presence of malicious or unexpected global values. --- packages/zone.js/lib/zone-impl.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/zone.js/lib/zone-impl.ts b/packages/zone.js/lib/zone-impl.ts index 4465bbaadeb..7697a7b2048 100644 --- a/packages/zone.js/lib/zone-impl.ts +++ b/packages/zone.js/lib/zone-impl.ts @@ -762,10 +762,20 @@ export type AmbientZone = Zone; const global = globalThis as any; -// __Zone_symbol_prefix global can be used to override the default zone -// symbol prefix with a custom one if needed. +// __Zone_symbol_prefix global can be used to override the default zone symbol +// prefix with a custom one if needed. The value must be a non-empty string +// containing only alphanumeric characters and underscores. Any other value +// (including DOM-clobbered objects, empty strings, or strings with special +// characters) is silently ignored and the default prefix is used instead. +// This guards against DOM clobbering attacks where an attacker sets +// __Zone_symbol_prefix to an HTMLElement via e.g. , +// which would otherwise corrupt all internal zone symbol key lookups. export function __symbol__(name: string) { - const symbolPrefix = global['__Zone_symbol_prefix'] || '__zone_symbol__'; + const rawPrefix = global['__Zone_symbol_prefix']; + const symbolPrefix = + typeof rawPrefix === 'string' && /^[a-zA-Z0-9_]+$/.test(rawPrefix) + ? rawPrefix + : '__zone_symbol__'; return symbolPrefix + name; }