Skip to content

fix(zone.js): harden zoneSymbolEventNames and patches against __proto__ key#69320

Open
arturovt wants to merge 1 commit into
angular:mainfrom
arturovt:fix/zone.js_harden_proto
Open

fix(zone.js): harden zoneSymbolEventNames and patches against __proto__ key#69320
arturovt wants to merge 1 commit into
angular:mainfrom
arturovt:fix/zone.js_harden_proto

Conversation

@arturovt

Copy link
Copy Markdown
Contributor

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:

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:

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:

Object.prototype.hasOwnProperty.call(patches, name)

since null-prototype objects do not inherit hasOwnProperty.

…__ 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`.
@pullapprove pullapprove Bot requested a review from crisbeto June 11, 2026 18:47
@angular-robot angular-robot Bot added the area: zones Issues related to zone.js label Jun 11, 2026
@ngbot ngbot Bot added this to the Backlog milestone Jun 11, 2026
@JeanMeche JeanMeche requested a review from atscott June 11, 2026 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: zones Issues related to zone.js

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant