Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Content Security Policy: Uncaught EvalError #468

Closed
tomjohn1028 opened this issue Oct 29, 2019 · 9 comments
Closed

Content Security Policy: Uncaught EvalError #468

tomjohn1028 opened this issue Oct 29, 2019 · 9 comments

Comments

@tomjohn1028
Copy link

Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' blob: filesystem:".

I'm using EJS to render templates in a Browser Extension and the use of new Function("return this;") is throwing a CSP error. I'm building from the npm package, but looked into the client side distribution and noticed the same eval occurs there as well. (https://github.com/mde/ejs/blob/v2.6.2/lib/ejs.js#L106)

Here's an example of a fix that works in the browser extension context. I'd be happy to open a PR and validate the fix in the context if it's an acceptable change.

@ExE-Boss
Copy link
Collaborator

That won’t work in this case, because EJS works by transpiling the .ejs file into a JavaScript function at runtime.

@chrisdlangton
Copy link

That won’t work in this case, because EJS works by transpiling the .ejs file into a JavaScript function at runtime.

that is not the way ejs was used where I worked, it's not how I use it today, and by looking at github search the first 3 i looked at don't use .ejs files either.

I actually can't even see why you would use .ejs files honestly, the beauty of ejs is in <template> elements combined with ejs.render which seems to be the most popular usage and does n;t require 'unsafe-eval' .

Perhaps anyone reading this, because they are using ejs on a site with CSP (where would you not want CSP !?!?) perhaps consider just forking the project
I've been running a 'vendored' fork for a while and am not complaining because of the very few releases (1 a year) I need to rebase.

Anyway, just thought i'd try to unvendor some forked projects that are poor security (like this one) turns out it is still ignoring CSP

@RyanZim
Copy link
Collaborator

RyanZim commented Jul 29, 2021

If somebody wants to submit a PR to fix this, preferably with an accompanying test case, we'd be happy to take a look. However, be aware, this is not the only instance where EJS uses Function

@chrisdlangton
Copy link

If somebody wants to submit a PR to fix this, preferably with an accompanying test case, we'd be happy to take a look. However, be aware, this is not the only instance where EJS uses Function

Sorry @RyanZim you won't like the state of mine, it's at least 50% removed code, such is the way of forks right?

If you are looking for a CSP friendly solution, you'll be removing functionality guaranteed. Mustache counldn't do it so the fork called micromusstache exists for this exact reason.

@RyanZim
Copy link
Collaborator

RyanZim commented Jul 30, 2021

Got it, yeah, a fork is probably a necessary evil in that case.

@gregmartyn
Copy link

The two usages I see are:

/**
 * Promise implementation -- defaults to the native implementation if available
 * This is mostly just for testability
 *
 * @type {PromiseConstructorLike}
 * @public
 */

exports.promiseImpl = (new Function('return this;'))().Promise;

and

        // Have to use generated function for this, since in envs without support,
        // it breaks in parsing
        try {
          ctor = (new Function('return (async function(){}).constructor;'))();
        }
        catch(e) {
          if (e instanceof SyntaxError) {
            throw new Error('This environment does not support async/await');
          }
          else {
            throw e;
          }
        }

Am I missing any others?

Based on a superficial understanding from the comments there, those fallbacks could be removed, leaving it up to the user to configure Babel/etc to be responsible for that legacy support instead. (This is pretty much unavoidable anyway for anyone still supporting IE11 but wanting to use many other common NPM libraries) Alternatively, that removal could be an opt-in if those blocks were surrounded by a conditional that checked something that could be hardcoded by DefinePlugin.

Removing the fallbacks would require a new major version, but the DefinePlugin approach wouldn't.

Async browser support: https://caniuse.com/async-functions
Promise browser support: https://caniuse.com/promises

What do you think? Is either of those options (or both?) a viable path forward?

Thanks.

@charles-dr
Copy link

I'm still running into the same issue.. Is there any update?

@0xisk
Copy link

0xisk commented Nov 15, 2022

We are integrating ejs with our extension, and we're getting this error:

Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' 'wasm-unsafe-eval'".

We found this potential solution that overcomes this security error (facebook/regenerator#336 (comment)) But it is not approved here yet, is there an update on this issue?

@mde
Copy link
Owner

mde commented Nov 20, 2022

I just did some checking up, and the fundamental problem is much deeper than just the use of the Function constructor to identify the global object. (The use of self to do that is a little hacky, but not terrible. It could be made to work for that specific purpose.)

The real problem is that EJS uses the same construct to execute the programmatically created string of JS source-code that dynamically renders each template. This is the heart of EJS.

We used to use eval for the same purpose, very early on, but switched to the Function constructor approach to ensure that the resulting code used the passed-in locals, and implied variables couldn't be created by apply or with after the fact. Worth noting that eval would almost certainly trigger the same CSP block, which is intended to block the ad-hoc execution of code that is very specifically what EJS is doing.

EJS is effectively a JavaScript runtime, and given how malleable JavaScript itself is, it can't be locked down and made completely safe at its point of execution. The documentation on CSP notes that the 'unsafe-eval' setting is there "to make CSP easier to adopt," which in this caes, practically speaking, means "continue allowing people to do genuinely useful things like templating and variable interpolation.'"

If anybody can come up with an alternative method for dynamically creating and executing JavaScript code on the fly, that doesn't run afoul of the CSP settings which seems specifically designed to prevent it, I am open to trying it. At this point, I am unaware of anything that will do that. I am closing this issue. Apologies for the length of time it remained open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants