Skip to content

Allow script-src 'unsafe-hashes' for eval() and new Function #623

@nicolo-ribaudo

Description

@nicolo-ribaudo

Right now the only way to allow eval (or the equivalent new Function) is by using the unsafe-eval policy. This policy should be used as little as possible, because it allows *any* usage of eval/Function rather than just a list of trusted ones.

One use case for eval is feature detection. When testing for new syntax you can wrap it in new Function and check whether it can be parsed or not. In this case strings are static, and so it's easy to hash them ahead of time and provide the has as part of the CSP:

let supportsDecorators = false;
try {
  new Function("@dec class A {}"); // allowed
  supportsDecorators = true;
} catch {}

import(supportsDecorators ? "./source.js" : "./transpiled.js");
</script>

another use case comes from the ShadowRealms TC39 proposal, that was recently demoted from Stage 3 to Stage 2 because the integration with the web platform is not fully flashed out yet.

That proposal exposes realms with a restricted interface to JavaScript, and there are two ways to run code in them:

  • synchronously, with a ShadowRealm.prototype.evaluate(code: string) method
  • asynchronously, with a ShadowRealm.prototype.importValue(moduleURL: string) method

.evaluate basically runs eval() inside the shadow realm, and for this reason it should follow normal CSP rules. However, under the existing policies this means that the only way to synchronously evaluate code in shadow realms is by using unsafe-eval.

How do you feel about extending hash-based policies to also support eval/new Function? This would make it possible to write the example above as follows:

<meta http-equiv="Content-Security-Policy" content="script-src 'unsafe-hashes' 'sha256-c25cd64187ae9eb96a23e52e9f55dfc4cf0fbf19f60885eca8abb94c9644a72a'">

<script>
let supportsDecorators = false;
try {
  new Function("@dec class A {}"); // allowed
  supportsDecorators = true;
} catch {}

import(supportsDecorators ? "./source.js" : "./transpiled.js");

new Function(someOtherString); // still disallowed!
</script>

and would work similarly with shadow realms.

An alternative, if we don't want to change the existing unsafe-hashes behavior, could be to introduce a new unsafe-eval-hashes policy.

(cc @ptomato, who is working with me on this)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions