Visitar URL original
fix(zone.js): harden zoneSymbolEventNames and patches against __proto… · angular/angular@2d33fd5 · GitHub
Skip to content

Commit 2d33fd5

Browse files
arturovtkirjs
authored andcommitted
fix(zone.js): harden zoneSymbolEventNames and patches against __proto__ key
Initialize `zoneSymbolEventNames` and `patches` with `Object.create(null)` instead of `{}`. This is a hardening change rather than a fix for an exploitable vulnerability. Calling `addEventListener('__proto__', fn)` is not directly attacker-controlled; its presence already implies an application bug. However, if such a call does occur, the current implementation can behave unexpectedly depending on the environment. For `zoneSymbolEventNames`, accessing `zoneSymbolEventNames['__proto__']` on a plain object invokes the inherited `__proto__` accessor and returns `Object.prototype`, which is truthy. This causes `prepareEventNames()` to be skipped, leaving `symbolEventName` undefined and eventually leading to a runtime error when `window['undefined'] = []` is executed. In Node.js environments running with `--disable-proto=throw`, the assignment: ```ts id="z8n4qm" zoneSymbolEventNames['__proto__'] = {}; ``` throws immediately because it triggers the disabled `__proto__` setter. The `patches` registry has a similar issue. A `__proto__` key passed to `__load_patch()` bypasses the duplicate-patch check and reaches: ```ts id="f3v7kx" patches['__proto__'] = fn(...); ``` which invokes the `__proto__` setter and changes the prototype of the `patches` object. Using `Object.create(null)` removes the inherited `__proto__` accessor entirely, causing these keys to behave like ordinary properties rather than interacting with JavaScript's prototype machinery. As part of this change, `patches.hasOwnProperty(name)` is also updated to: ```ts id="n2c8wp" Object.prototype.hasOwnProperty.call(patches, name) ``` since null-prototype objects do not inherit `hasOwnProperty`.
1 parent 8d31b82 commit 2d33fd5

4 files changed

Lines changed: 9 additions & 7 deletions

File tree

‎packages/zone.js/lib/common/utils.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ export const isMix: boolean =
129129
!isWebWorker &&
130130
!!(isWindowExists && internalWindow['HTMLElement']);
131131

132-
const zoneSymbolEventNames: {[eventName: string]: string} = {};
132+
// tslint:disable-next-line:no-toplevel-property-access
133+
const zoneSymbolEventNames: {[eventName: string]: string} = Object.create(null);
133134

134135
const enableBeforeunloadSymbol = zoneSymbol('enable_beforeunload');
135136

‎packages/zone.js/lib/zone-impl.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,7 @@ export function initZone(): ZoneType {
814814
}
815815

816816
static __load_patch(name: string, fn: PatchFn, ignoreDuplicate = false): void {
817-
if (patches.hasOwnProperty(name)) {
817+
if (Object.hasOwn(patches, name)) {
818818
// `checkDuplicate` option is defined from global variable
819819
// so it works for all modules.
820820
// `ignoreDuplicate` can work for the specified module
@@ -1601,7 +1601,7 @@ export function initZone(): ZoneType {
16011601
macroTask: 'macroTask' = 'macroTask',
16021602
eventTask: 'eventTask' = 'eventTask';
16031603

1604-
const patches: {[key: string]: any} = {};
1604+
const patches: {[key: string]: any} = Object.create(null);
16051605
const _api: ZonePrivate = {
16061606
symbol: __symbol__,
16071607
currentZoneFrame: () => _currentZoneFrame,

‎packages/zone.js/test/typings/tsconfig.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"noEmitOnError": false,
1414
"stripInternal": false,
1515
"strict": true,
16-
"lib": ["es5", "dom", "es2015.collection", "es2015.iterable", "es2015.promise"]
16+
"lib": ["es5", "dom", "es2015.collection", "es2015.iterable", "es2015.promise", "es2022.object"]
1717
},
1818
"files": ["./type.test.ts", "./node_modules/zone.js/zone.ts"]
1919
}

‎packages/zone.js/tsconfig.json‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"es2015.iterable",
1919
"es2015.promise",
2020
"es2015.symbol",
21-
"es2015.symbol.wellknown"
22-
],
23-
},
21+
"es2015.symbol.wellknown",
22+
"es2022.object"
23+
]
24+
}
2425
}

0 commit comments

Comments
 (0)