Open Bug 1591983 Opened 21 days ago Updated 4 days ago

Content scripts window.eval should not be subjected to CSP restrictions

Categories

(WebExtensions :: General, enhancement, P3)

enhancement

Tracking

(Not tracked)

People

(Reporter: tartpvule_ggi, Unassigned)

References

(Blocks 1 open bug)

Details

As stated in https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#Using_eval()_in_content_scripts

  1. Make a WebExtension with content script doing window.eval("(function() { alert('Hello World') })()")
  2. Navigate to a page with CSP directives set to block eval e.g. www.github.com

Current Result:
No alert box appears.
In browser console: EvalError: call to eval() blocked by CSP

Suggestion:
window.eval calls from a WebExtension addon should not be subjected to the content page's CSP directives.

Related but not quite the same:
Bug 1267027 about content inserted into the page DOM
Bug 1580514 about eval-ing from devtools

Summary: Content scripts window.eval should not be subjected to CSP restructions → Content scripts window.eval should not be subjected to CSP restrictions

Currently all forms of inline code are blocked. Not just window.eval, but also inline <script> elements.

In Chrome, inline scripts are allowed, regardless of CSP. window.eval executes in the context of the content script instead of the web page, so the behavior there is not as relevant.

Depending on your constraints, there may be alternatives that you can use:

If you really need to immediately run arbitrary code in the context of the page in the presence of a strict CSP, then you're out of luck (for now?).

Blocks: 1267027
Status: UNCONFIRMED → NEW
Ever confirmed: true
See Also: → 1580514

I guess I'm out of luck. :( :(
I have a private (will never be released) extension that instruments and extensively interferes with a hostile page's script.
A large part could be done with exportFunction, but that doesn't cover everything I require, for example

  1. Creating a constructor such that (new testFn()) instanceof testFn === true requires something monstrous like
var _prototype = (new window.Object()).wrappedJSObject;
var testFn = exportFunction(function() {
 var obj = window.Object.wrappedJSObject.create(testFn.prototype);
 return obj;
}, window).wrappedJSObject;
testFn.prototype = _prototype;
window.wrappedJSObject.testFn = testFn;

Detecting the case where it's called as a mixin constructor requires more black magic with XPCNativeWrapper.unwrap (undocumented).
2. It cannot create other kinds of function that is not plain old classic ones, like arrow functions and member functions, such that toString spits out the correct kind of code.
3. Function forwarders have a lot of overhead per call compared to a plain function created with a window.eval.

Maybe exportFunction could be improved? But that's another issue, I guess.

Have you looked into the Proxy API? This API is designed for transparently wrapping JavaScript objects and functions to change or inspect their runtime behavior.
Documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

Thank you for the information about Proxy.
It works, but 1) it's at least 300x slower, and 2) (new Proxy(()=>{}, {})).toString() doesn't return a string of an arrow function
I have been avoiding Proxys due to the very poor performance. Will use it as a fallback.
Still would love an unrestricted window.eval.

P.S. I know number 2 is a strange thing to ask for, but well, it's to be as stealthy as possible to hostile code.

Priority: -- → P3
You need to log in before you can comment on or make changes to this bug.