fix(zone.js): validate __Zone_symbol_prefix to prevent DOM clobbering attacks

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.

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.

(cherry picked from commit e50f504b2f)
This commit is contained in:
arturovt
2026-05-23 23:16:02 +03:00
committed by Pawel Kozlowski
parent f6d8e642b0
commit 34c4e401ba
+5 -3
View File
@@ -762,10 +762,12 @@ 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 can be set globally to override the default zone symbol prefix.
export function __symbol__(name: string) {
const symbolPrefix = global['__Zone_symbol_prefix'] || '__zone_symbol__';
const rawPrefix = global['__Zone_symbol_prefix'];
// Guard against DOM clobbering: an attacker can set __Zone_symbol_prefix to an HTMLElement
// via e.g. <input name="__Zone_symbol_prefix">, so we only trust it if it's actually a string.
const symbolPrefix = typeof rawPrefix === 'string' ? rawPrefix : '__zone_symbol__';
return symbolPrefix + name;
}