23 Commits

Author SHA1 Message Date
Kristiyan Kostadinov 732e505018 fix(core): replace all hasOwnProperty usages with Object.hasOwn
We keep getting PRs that target single usages of `hasOwnProperty` and we have ~100 of them. These changes aim to address the issue centrally by swapping out all the instances and adding a lint rule against introducing new ones.
2026-08-18 09:17:18 -07:00
arturovt 2d33fd55ff 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`.
2026-06-24 12:19:30 -04:00
arturovt e50f504b2f 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.
2026-05-29 14:54:13 +02:00
Andrew Scott fa7580061b fix(zone.js): avoid type error on custom object rejection with rejection property
Ensure that when a custom object with a 'rejection' property is thrown as a raw promise rejection, the unhandled promise rejection error logger does not crash with a TypeError while trying to access undefined zone properties.

Also wrap microtask queue draining and task frame counter updates with defensive try-finally blocks to guarantee internal scheduler states are properly reset under any potential call stack exception unwinding scenarios.
2026-05-27 10:45:13 -07:00
arturovt fc6a7eea68 fix(zone.js): allow draining microtasks in Promise.then (through flag)
These changes are essentially the same as those introduced in
angular#45273, but they include backward compatibility
for applications that explicitly rely on the order in which microtasks are drained.

This is critically important for our code and other third-party code, which is
beyond our control, to work properly. If a microtask is scheduled within an event
listener to be executed "later", it should indeed be executed later and not synchronously,
as this would break the expected flow of code execution.

The simple code that reproduces the behavior that exists now:

```ts
Zone.current.fork({name: 'child'}).run(() => {
  const div = document.createElement('div');
  div.style.height = '200px';
  div.style.width = '200px';
  div.style.backgroundColor = 'red';
  document.body.appendChild(div);

  function listener() {
    Promise.resolve().then(() => {
      div.style.height = '400px';
    });
  }

  div.addEventListener('fakeEvent', listener);
  div.dispatchEvent(new Event('fakeEvent'));
  console.log(div.getBoundingClientRect().height); // 400
});
```

The code above logs 400 as the height, but it should actually log 200 because the
height is updated in a microtask within the event listener.

When using Angular with microfrontend applications, especially when other apps might be
using React, zone.js can disrupt the classical order of operations. For example, when using a
`react-component/trigger`, it schedules a microtask within an event listener using
`Promise.resolve().then(...)` to determine whether the event needs to be re-dispatched.
The event is re-dispatched when the layout has changed, which is why a microtask is used.

With this change, we introduce a global configuration flag,
`__zone_symbol__enable_native_microtask_draining`, to allow consumers to enable
microtask draining within a browser microtask.

This flag is necessary to prevent any breaking changes resulting from this modification.
The previous attempt to address this issue caused a significant number of failures in g3.
Therefore, we are hiding that fix behind the configuration flag.

Closes angular#44446
Closes angular#55590
Closes angular#51328
2026-04-15 10:31:28 -04:00
Matthieu Riegler 2e4659648a refactor(zone.js): remove legacy browser support (#63511)
This commit removes the support for legacy browsers.

BREAKING CHANGE: IE/Non-Chromium Edge are not supported anymore.

PR Close #63511
2025-10-16 14:58:45 +00:00
Johnson Chu a6cdbec09f refactor: remove unnecessary TSLint rule flags (#59365)
There are many TSLint rule flags in the source code that have no effect, and they can be safely removed to keep the code clean.

PR Close #59365
2025-01-07 16:06:21 +00:00
Costin Sin 2e54d6dea8 refactor(zone.js): Change the type of _taskCounts to an IndexSignature that can have keys (#51739)
named as the values of the `TaskType` type.

The Closure Compiler used at Google has a property renaming optimization
that can change the property names when minifying code. Having the
correct type helps the TSJS team that develops a tool to identfy
property renaming issues directly in TypeScript.

Signed-off-by: Costin Sin <sin.costinrobert@gmail.com>

PR Close #51739
2024-11-01 15:44:06 +00:00
Joey Perrott 9dbe6fc18b refactor: update license text to point to angular.dev (#57901)
Update license text to point to angular.dev instead of angular.io

PR Close #57901
2024-09-24 15:33:00 +02:00
Alan Agius 982f1b1251 fix(zone.js): support Timeout.refresh in Node.js (#56852)
The `Timeout` object in Node.js has a `refresh` method, used to restart `setTimeout`/`setInterval` timers. Before this commit, `Timeout.refresh` was not handled, leading to memory leaks when using `fetch` in Node.js. This issue arose because `undici` (the Node.js fetch implementation) uses a refreshed `setTimeout` for cleanup operations.

For reference, see: https://github.com/nodejs/undici/blob/1dff4fd9b1b2cee97c5f8cf44041521a62d3f133/lib/util/timers.js#L45

Fixes: #56586

PR Close #56852
2024-07-16 12:46:51 -07:00
Kristiyan Kostadinov aa8df1d029 refactor(core): clean up clang comments and workarounds (#55750)
Since we aren't using clang anymore, we can remove the comments and the workarounds that were in place to prevent it from doing the wrong thing.

PR Close #55750
2024-05-13 11:10:36 -07:00
Joey Perrott f307e95459 refactor: migrate zone.js to prettier formatting (#55427)
Migrate formatting to prettier for zone.js from clang-format

PR Close #55427
2024-04-29 09:52:05 -07:00
Andrew Scott b3d045b9a4 fix(zone.js): Add 'declare' to each interface to prevent renaming (#54966)
This commit adds `declare` to each interface in the `zone-impl` to
prevent renaming of any interface properties by compiler optimizations.
This would otherwise cause issues if multiple applications depend on ZoneJS and
compile the interface properties to different names.

PR Close #54966
2024-03-20 09:16:07 -07:00
Doug Parker 5328be6660 refactor(zone.js): formatting recently changed files (#53443)
For some reason CI started complaining about lack of formatting here.

PR Close #53443
2024-03-15 18:11:34 -07:00
Doug Parker 5e45bb771b refactor(zone.js): delay reading __Zone_symbol_prefix until needed (#53443)
While reading this is not a top-level side effect, it does _depend_ on a top-level side effect. Specifically, `node-env-setup.ts` set this value. Now that its side effect is moved into a function, we can't read it as the top-level of `zone-impl.ts` and need to wait until `__symbol__` is actually called outside of top-level scope.

PR Close #53443
2024-03-15 18:11:34 -07:00
Doug Parker d8db402833 refactor(zone.js): move duplicate Zone check into zone.ts file (#53443)
`zone.ts` contains the global variable definition and is the appropriate place for an error side effect when Zone is initialized twice.

PR Close #53443
2024-03-15 18:11:33 -07:00
Doug Parker 4876ed9510 refactor(zone.js): rename types to drop the _ prefix convention (#53443)
Now that we have real ES modules, there's no need for the prefix convention.

PR Close #53443
2024-03-15 18:11:33 -07:00
Doug Parker 6c7e1e61c6 refactor(zone.js): export Zone initialization function instead of invoking it as an IIFE (#53443)
This removes the top-level side effects from this file. Indenting is left as-is to minimize changes.

PR Close #53443
2024-03-15 18:11:33 -07:00
Doug Parker 17c59eb962 refactor(zone.js): rename Zone class to ZoneImpl (#53443)
This removes a name collision on `Zone` with the interface. Otherwise putting the `interface Zone {}` and `class Zone {}` in the same scope when the IIFE is removed will cause a conflict.

PR Close #53443
2024-03-15 18:11:33 -07:00
Doug Parker 482335657b refactor(zone.js): moves global constant outside IIFE (#53443)
The IIFE will be removed shortly to support exporting symbols inside it.

PR Close #53443
2024-03-15 18:11:33 -07:00
Doug Parker 4feec728c0 refactor(zone.js): export previously global types from zone-impl.ts. (#53443)
This allows the types to be directly imported when used.

PR Close #53443
2024-03-15 18:11:33 -07:00
Doug Parker 76d8c7344e refactor(zone.js): remove declare global from zone-impl.ts (#53443)
This drops global declarations from this file (as they will be limited to `zone.ts`. It also deletes the `/** @internal */` annotation on `AmbientZone` which is no longer necessary since it isn't in the `declare global` and deletes the global Zone declaration which is also unnecessary.

PR Close #53443
2024-03-15 18:11:32 -07:00
Doug Parker a760470b20 refactor(zone.js): copy zone.ts to zone-impl.ts (#53443)
This is just a straight copy, no code is altered. The new `zone-impl.ts` file will contain the actual definitions exported directly without any global declarations or top-level side effects. The existing `zone.ts` will remain as an entry point with those globals and side-effects.

PR Close #53443
2024-03-15 18:11:32 -07:00