WebExtensions – frame same origin policy – why?

Frame scripts in bootstrapped add-ons can enter any frame, regardless of whether the parent and the frame have the same origin or not. I find this very convenient. In VimFx I have this function:

function querySelectorAllDeep(window, selector) {
  const elements = Array.from(window.document.querySelectorAll(selector))
  for (const frame of window.frames) {
    elements.push(...querySelectorAllDeep(frame, selector))
  }
  return elements
}

For example, it allows me to easily find every single link on the screen (no matter how many nested frames there might be on the page).

With WebExtensions, though, the good old “same origin” policy applies. As far as I can see, I need to load a content script into every frame and use window.postMessage to communicate between them, which is a whole lot fiddlier (but doable).

Is there a reason why content scripts in WebExtensions have this restriction, when frame scripts in bootstrapped add-ons seem to work so well?

I think on the implementation level the reason for this is that the content_scripts are exectuted in a Cu.createSandbox(), which inherits most of it’s escurety aspects from the content window.

I do not think there is a conceptional reason for it. Same as I don’t see a reason why it is impossible to evaluate code in a page that was served with a strong CSP.

WebExtensions are designed to have more restrictive security. This bug seems related to what you’re asking.

Thanks for your answers, and sorry for a super late reply!

This may or may not provide better security, but one thing mentioned in bug 1214373 caught my attention:

It would also help us avoid some issues with dead wrappers, and inner windows changing without the extension code noticing.

That is enough to convince me that the change is a good idea. Working with Components.utils.isDeadWrapper has been a pain in VimFx, which I’ll happily avoid (even if it means more complicated code when it comes to frame handling).

Thanks! :slight_smile: