Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
dotproto opened this issue Oct 31, 2022 · 14 comments

Comments

@dotproto
Copy link
Contributor

dotproto commented Oct 31, 2022

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
@tophf
Copy link

tophf commented Nov 2, 2022

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}));

@dotproto dotproto changed the title Demo request: Calling .click() on an element with an inline event handler or link with a javascript: scheme Sample: Calling .click() on an element with an inline event handler or link with a javascript: scheme Nov 2, 2022
@guest271314

This comment was marked as off-topic.

@blairjo
Copy link

blairjo commented Mar 7, 2024

This issue has been open for a while, although I can see a new sample was pushed by @daidr but never accepted: #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?

@oliverdunk
Copy link
Member

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.

@blairjo
Copy link

blairjo commented Mar 7, 2024

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 :)

@oliverdunk
Copy link
Member

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.

@blairjo
Copy link

blairjo commented Mar 7, 2024

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.

@tophf
Copy link

tophf commented Mar 7, 2024

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
Copy link

tophf commented Mar 7, 2024

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
Copy link

tophf commented Mar 7, 2024

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].

@blairjo
Copy link

blairjo commented May 9, 2024

Hi @oliverdunk,

Has there been any progress on "something more elegant"?
Another couple of months has gone by and the upgrade deadline is now just a few weeks away... I need to know whether to bute the bullet and implement this solution or whether there is something better?

@oliverdunk
Copy link
Member

Has there been any progress on "something more elegant"?

Hi @blairjo, I don't have anything specific to share I'm afraid. We did have some good discussions about running code in the main world at our last in person Web Extensions Community Group meeting - it seems like we continue to agree that something like chrome.dom.executeScript to run code in the main world from a content script would be helpful. We don't have a timeline to implement this though.

Another couple of months has gone by and the upgrade deadline is now just a few weeks away... I need to know whether to bute the bullet and implement this solution or whether there is something better?

For the June deadline, I would definitely suggest implementing the event approach. We're aware of the use case and do want to make it easier, but there are no plans to release anything in the short term.

@blairjo
Copy link

blairjo commented May 9, 2024

@oliverdunk perhaps I'm missing the point but it doesn't feel like a workaround of any sort should be necessary. If my extension simply clicks a DOM element, the extension itself is not violating any CSP policy - the problem is the target site itself has the inline code in the click event, which obviously I can't control. It feels wrong to me that this is blocked - all my extension wants to do is click a link!

That being said, I have been patiently waiting for some movement on this and it seems like nothing is going to happen any time soon, which gives me a very small window to fix and test using this workaround. Is it possible to request an extension to the V3 deadline for a specific Chrome Extension?

@oliverdunk
Copy link
Member

@oliverdunk perhaps I'm missing the point but it doesn't feel like a workaround of any sort should be necessary.

I don't necessarily disagree, your use case seems entirely valid and it would be nice to make easier. The workaround is fairly minimal though and with it you should be able to do everything you can in MV2. With that in mind, I'm still not convinced this is a big problem.

It isn't possible to request an extension to the MV2 deprecation timeline I'm afraid.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants