Repository: sinonjs/fake-timers (js)

Issue:
Not resilient to modification of globals 
The library does not resist destructive changes of the globals. As I initially reported the issue at https://github.com/vitest-dev/vitest/issues/7024 I wanted to make you aware of the problem.

One fix, if you consider that it should be fixed, would be to capture the globals for Intl and Date when the code got imported.

Feel free to close, if the behavior is expected.

---

_If the suggestion is relevant I can propose a fix._

Pull request description:
fix: Resilient to prototype pollution of Intl
#### Purpose (TL;DR) - mandatory

This PR is supposed to fix #516. It should make fake-times a bit more resilient to prototype poisoning occurring directly on `Intl`. That said it does not handle deeper prototype breakings.

<!--
> give a concise (one or two short sentences) description of what problem is being solved by this PR
>
> Example: Fix issue #123456 by re-structuring the colour selection conditional in method `paintBlue`
-->

<!--
#### Background (Problem in detail)  - optional
-->
<!--
> When relevant, give a more thorough description of what the problem the PR is trying to solve. Examples of good topics for this section are:
> * Link to an existing GitHub issue describing the problem
> * Describing the problem in greater detail than the TL;DR section above
> * How you discovered the issue if it's not already described as an issue on GitHub
> * Discussion of different approaches to solving this problem and why you chose your proposed solution
-->

<!--
#### Solution  - optional
-->
<!--
> When contributing code (and not just fixing typos, documentation and configuration), please describe why/how your solution works. This helps reviewers spot any mistakes in the implementation.
>
> Example:
> "This solution works by adding a `paintBlue()` method"
> Then your reviewer might spot a mistake in the implementation, if `paintBlue()` uses the colour red.
-->


Patch:
diff --git a/src/fake-timers-src.js b/src/fake-timers-src.js
index 03ad8d5..11dab90 100644
--- a/src/fake-timers-src.js
+++ b/src/fake-timers-src.js
@@ -206,7 +206,12 @@ function withGlobal(_global) {
     }
 
     const NativeDate = _global.Date;
-    const NativeIntl = _global.Intl;
+    const NativeIntl = isPresent.Intl
+        ? Object.defineProperties(
+              Object.create(null),
+              Object.getOwnPropertyDescriptors(_global.Intl),
+          )
+        : undefined;
     let uniqueTimerId = idCounterStart;
 
     if (NativeDate === undefined) {
@@ -1107,7 +1112,7 @@ function withGlobal(_global) {
     }
 
     if (isPresent.Intl) {
-        timers.Intl = _global.Intl;
+        timers.Intl = NativeIntl;
     }
 
     const originalSetTimeout = _global.setImmediate || _global.setTimeout;


Test patch:
diff --git a/test/issue-516-test.js b/test/issue-516-test.js
new file mode 100644
index 0000000..b21ed3b
--- /dev/null
+++ b/test/issue-516-test.js
@@ -0,0 +1,20 @@
+"use strict";
+
+const { FakeTimers } = require("./helpers/setup-tests");
+
+describe("issue #516 - not resilient to changes on Intl", function () {
+    it("should successfully install the timer", function () {
+        const originalIntlProperties = Object.getOwnPropertyDescriptors(
+            global.Intl,
+        );
+        for (const key of Object.keys(originalIntlProperties)) {
+            delete global.Intl[key];
+        }
+        try {
+            const clock = FakeTimers.createClock();
+            clock.tick(16);
+        } finally {
+            Object.defineProperties(global.Intl, originalIntlProperties);
+        }
+    });
+});