'What does --frozen-intrinsics flag do in node.js?

The documentation for --frozen-intrinsics says:

Only the root context is supported. There is no guarantee that globalThis.Array is indeed the default intrinsic reference. Code may break under this flag

I couldn't understand this. Can someone help me understand this in simple words with an example?

Background: I was checking nicolo-ribaudo/jest-light-runner where there is a mention of --frozen-intrinsics.



Solution 1:[1]

When you use --frozen-intrinsics, all the built-in JavaScript objects and functions are recursively frozen, except for globalThis.

If you run node --frozen-intrinsics, you can check it:

> Object.isFrozen(Array)
true
> Object.isFrozen(Array.prototype)
true
> Object.isFrozen(globalThis);
false
> Array.isArray = () => true; Array.isArray(2); // you cannot modify built-in properties, this will not return true
false
> globalThis.foo = 3; foo; // you can still define new globals
3
> globalThis.Array = 4; Array; // However, you can also replace existing globals
4

This prevents your code from accidentally modifying globals, so I recommended it in jest-light-runner to prevent tests from accidentally influencing each other (since it doesn't isolate test files like Jest's default runner does). Note that you still have a communication channel by attaching new properties to the global object, so it's not an isolation mechanism.

Now, lets take a look at the docs you quoted.

Only the root context is supported.

In Node.js, you can create multiple "global contexts" using the vm built-in module. --frozen-intrinsics does not affect those contexts, so if you run node with --frozen-intrinsics:

> Object.isFrozen(Array)
true
> Object.isFrozen(require("vm").runInNewContext("Array"))
false

There is no guarantee that globalThis.Array is indeed the default intrinsic reference.

As mentioned earlier, globalThis.Array could still be replaced. However, if you have a "safe reference" to an object (either using syntax, or by storing the original Array global in a local variable), you can be sure that it's not modified:

let OriginalArray = Array;

require("untrusted-module");

globalThis.Array; // this might have been replaces
[].push; // this is still the original one
OriginalArray.isArray; // this is still the original one

Code may break under this flag

If code needs to modify built-ins, it would obviously stop working. For example, you cannot use polyfills that modify the global objects.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1