chrome-extensions-samples icon indicating copy to clipboard operation
chrome-extensions-samples copied to clipboard

Sample: Calling .click() on an element with an inline event handler or link with a javascript: scheme

Open dotproto opened this issue 1 year ago • 14 comments

Summary

Manifest V3's CSP for content scripts prevents extensions from executing inline JavaScript. Typically inline script execution would occur when an element has inline event handlers bound or when an anchor tag's href attribute contains a javascript: scheme. As a result, if an extension tries to call .click() on such an element inside an isolated world content script, Chrome will throw a CSP error.

This demo should show at least one safe way that developers can work around this issue.

Suggested implementation

Create a main world script (proxy-click.js?) that performs the click in the main world on behalf of the isolated script. At the moment I see a couple different ways we could approach this.

  1. Inject both a main and isolated world script as functions with a nonce as the args. Use this to dispatch a custom event with the nonce in the name in order to prevent other scripts from seeing the messages passed between main and isolated worlds.
  2. Inject a main world script a document start, append an event listener to window, & listen for something like 'proxy-click'. When dispatching this event from the isolated world, emit as a capture event and in the handler use stopPropagation() to minimize visibility.
  3. On demand, inject a main world script function with a CSS selector arg to perform the click.

Of these, at the moment (1) seems best.

Additional context

  • Issue 1299742: MV3 content script can't click a web page link with a javascript: URL

dotproto avatar Oct 31 '22 16:10 dotproto

CSS selector arg

A better solution is to send the node itself, which will also allow clicking inside closed shadow roots:

const elem = document.querySelector('a[onclick^="javascript:"]');
window.dispatchEvent(new MouseEvent(eventId, {relatedTarget: elem}));

tophf avatar Nov 02 '22 07:11 tophf

A rather elaborate workaround for this would be to get the text in console.log() set the inline event handler, then set the href to an empty string, define an event handler with addEventListener() and the handler including console.log() with the extracted string passed, then call click().

Another elaborate option is to again try to parse the existing JavaScript after javascript:, keep a .wat template which will be modified, then use WebAssembly.instantiate() and env to print the text.

guest271314 avatar Nov 06 '22 20:11 guest271314

This issue has been open for a while, although I can see a new sample was pushed by @daidr but never accepted: https://github.com/GoogleChrome/chrome-extensions-samples/pull/849

Is this a viable workaround to the issue of being able to click an element with inline code?

I'm not sure whether the issue / MR was never accepted because it didn't solve the problem, or could it be that the workaround is no longer necessary in later versions of Chrome?

blairjo avatar Mar 07 '24 14:03 blairjo

Is this a viable workaround to the issue of being able to click an element with inline code?

Hi @blairjo, this is still an issue and I think the workaround in that PR is totally viable (feel free to use it if it works for you). The reason for not merging it is that it definitely is a workaround, and I wanted to see if we could come up with something more elegant. The intent wasn't for it to stick around for so long though so definitely want to try and either come up with something better soon or just merge it.

oliverdunk avatar Mar 07 '24 14:03 oliverdunk

Hi @oliverdunk, thanks for the reply, The clock is ticking on the manifest V2 phase out though - we only have until June this year to upgrade as you know, and so if the Chromium team is going to come up with something better, it needs to be soon :)

blairjo avatar Mar 07 '24 14:03 blairjo

The clock is ticking on the manifest V2 phase out though - we only have until June this year to upgrade as you know, and so if the Chromium team is going to come up with something better, it needs to be soon :)

This isn't something we have seen many developers encountering and as a result it's not something we are considering a blocker for the deprecation. If you have interesting use cases where you're running into it though, I'd love to know.

oliverdunk avatar Mar 07 '24 14:03 oliverdunk

Hi @oliverdunk, my particular issue is that my extension is build to interact with a third party site that I have no control over. The site is fairly old and contains inline code that fires if you click on links. If my extension tries to click the link by calling .click() then I get the CSP violation error, even though it is not my extension that contains the inline code but the target site.

This bug was raised 2 years ago, but no action on it as far as I can see: https://issues.chromium.org/issues/40215987

Let me know if you need any further info, as this has definitely been a blocker for me upgrading.

blairjo avatar Mar 07 '24 14:03 blairjo

oliverdunk, you don't have the statistics judging by chrome://histograms, so your claim has no objective value. The problem with bugs like this one is that people running into it may not report it to the extension author and instead they just uninstall the extension.

tophf avatar Mar 07 '24 14:03 tophf

The site is fairly old and contains inline code that fires if you click on links

There's still a lot of sites with JS code in onclick, it's not something super rare.

tophf avatar Mar 07 '24 15:03 tophf

BTW that linked example is not really usable due to a hard-coded event id, which makes it prone to clashing with another extension and abuse by sites which sometimes may try to thwart an extension for whatever reason.

A usable example would have to call chrome.scripting.executeScript with a random event id in args inside the background script or a web_accessible_resources iframe inside Shadow DOM to prevent interfering with the site's logic due to window[0].

tophf avatar Mar 07 '24 15:03 tophf