Search code examples
javascriptbrowsersandboxexecutionuserscripts

Why do userscript managers still suport the use of unsafeWindow?


unsafeWindow API was made so that userscripts could interact with the variables and functions of the pages the script executed on. However it is strongly discouraged as websites could then hijack userscripts through unsafeWindow and make them execute malicious code. However, why was unsafeWindow even necessary and why is it still used? Previously until Firefox 39, users were able to use the location hack as an alternative to unsafeWindow. This hack eventually stopped working due to an update in Firefox 39 which patched this. Despite this, users could still use GM APIs in the isolated sandbox and insert code through a script tag like this:

const fnToRunOnNativePage = () => {
  console.log('fnToRunOnNativePage');
};

const script = document.body.appendChild(document.createElement('script'));
script.textContent = '(' + fnToRunOnNativePage.toString() + ')();';
// to use information inside the function that was retrieved elsewhere in the script,
// pass arguments above
script.remove();

I got this code from this stackoverflow post: How do I make my userscript execute code in isolated sandbox and unsafeWindow too?

So why is unsafeWindow is still useable? The code above is an almost perfect alternative to unsafeWindow. Also as a side note, is there any difference in the way unsafeWindow runs in Greasemonkey and Tampermonkey? Thanks.

External Resources:


Solution

  • Let's call the creation of a <script> tag and inserting it into the page script injection.

    Script injection has some drawbacks. To quote Brock Adams:

    1. The script, at least the injected parts, cannot use the enhanced privileges (especially cross-domain) provided by the GM_ functions -- especially GM_xmlhttpRequest().
    1. Can cause side effects or conflicts with the page's JS.
    1. Using external libraries introduces even more conflicts and timing issues. It's nowhere near as easy as @require.
      @require, also runs the external JS from a local copy -- speeding execution and all but eliminating reliance on an external server.
    1. The page can see, use, change, or block the script.
    1. Requires JS to be enabled. Firefox Greasemonkey, especially, can run on a page which has JS blocked. This can be godsend on bloated, crappy, and/or intrusive pages.

    So, some developers may prefer to use unsafeWindow than to use script injection. Removing unsafeWindow would make things harder for them.

    unsafeWindow often just works, and it can be less cumbersome than the creation and injection of a script tag.

    Another issue is that, on the web, backwards compatibility is often one of the most important factors that is rarely, if ever, given up. If something works in a 2015 version of something, the general philosophy is that it should work in the 2020 version too, without requiring whoever worked on the 2015 version to come back and fix it (since they may not be around to do so anymore). Related discussion here. While userscript managers don't have to care as much about backwards compatibility as other things on the web, the same sort of reasoning applies - avoid breaking things that are currently working unless you have a really good reason.