fix(zone.js): harden zoneSymbolEventNames and patches against __proto__ key#69320
Open
arturovt wants to merge 1 commit into
Open
fix(zone.js): harden zoneSymbolEventNames and patches against __proto__ key#69320arturovt wants to merge 1 commit into
arturovt wants to merge 1 commit into
Conversation
…__ 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`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Initialize
zoneSymbolEventNamesandpatcheswithObject.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, accessingzoneSymbolEventNames['__proto__']on a plain object invokes the inherited__proto__accessor and returnsObject.prototype, which is truthy. This causesprepareEventNames()to be skipped, leavingsymbolEventNameundefined and eventually leading to a runtime error whenwindow['undefined'] = []is executed.In Node.js environments running with
--disable-proto=throw, the assignment:throws immediately because it triggers the disabled
__proto__setter.The
patchesregistry has a similar issue. A__proto__key passed to__load_patch()bypasses the duplicate-patch check and reaches:which invokes the
__proto__setter and changes the prototype of thepatchesobject.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:since null-prototype objects do not inherit
hasOwnProperty.