-2

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:

Swangie
  • 175
  • 8

2 Answers2

1

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.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
0

In addition to the excellent explanation by CertainPerformance, unsafeWindow is simply implemented as an alias of window.wrappedJSObject.

As a script-manager developer myself, initially, I resisted the implementation of unsafeWindow but later had to add it for compatibility.

Modern browsers separate the JavaScript injected by the extension from the web page JavaScript, for security reasons.

Firefox goes further with a dedicated userScripts API to further limit the access of userscripts (i.e. 3rd party scripts) in comparison to extension's own scripts.

Bridging between these separated scopes/contexts (page, extension, userscript) increases the security concerns.

However, such interaction is sometimes needed to overwrite (undesirable) page JavaScript which can be a good thing, or to get data that is stored in the page JavaScript.

In conclusion, although unsafeWindow creates the possibility of unsafe bridges, it is not a new bridge and the same access is already available with window.wrappedJSObject.

erosman
  • 7,094
  • 7
  • 27
  • 46