5

I'm making an extension for chrome where the user can input a script, then press "run" to inject it into the current tab. I am using MV3 (manifest v3). Are there any ways to do this?

My code:

HTML:

<div class="scriptrunner">
    <h1>Script Runner</h1>
    <textarea placeholder="Enter script here" id="script"></textarea>
    <button id="run">Run Script</button>
</div>

Javascript:

let button = document.getElementById("run");
button.addEventListener("click", async () => {
    let input = document.getElementById("script");
    let script = input.value;
    // this is where the script would be ran
});

I've tried the following:

  • Using chrome.scripting.executeScript()
  • Using eval()
  • Using chrome.scripting.executeScript() to insert a script tag with a function, then running the function

I just started working on chrome extensions, so maybe I missed something, or this is just impossible.

Mood
  • 153
  • 1
  • 8

1 Answers1

9

Executing arbitrary user code (userscripts) isn't yet implemented in ManifestV3 and is still forbidden by the policies of Chrome's Web store for extensions.

The personal workaround (until the userscript API is implemented) is to create the code in the unsafe page context (MAIN world) and not in the default ISOLATED world of a content script.

You can safely use it in an unpacked extension, but using it in a web store extension is a risk as it violates their policy so your extension and maybe even your account will be disabled/removed if they find out during the review of your code.

async function execInPage(code) {
  const [tab] = await chrome.tabs.query({currentWindow: true, active: true});
  chrome.scripting.executeScript({
    target: {tabId: tab.id},
    func: code => {
      const el = document.createElement('script');
      el.textContent = code;
      document.documentElement.appendChild(el);
      el.remove();
    },
    args: [code],
    world: 'MAIN',
    //injectImmediately: true, // Chrome 102+
  });
}

execInPage('console.log(123)');

Warning! This may be blocked by the site if it has a strict Content-Security-Policy, in which case you can remove this header via declarativeNetRequest API.

wOxxOm
  • 65,848
  • 11
  • 132
  • 136
  • Thanks so much! However, this script only works on certain websites. On some, it throws the error `Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self'`. Is there any way to fix this? – Mood Feb 02 '22 at 21:35
  • 2
    It means these sites have a strict CSP which you'll have to disable or circumvent e.g. by removing `Content-Security-Policy` header using [declarativeNetRequest](https://developer.chrome.com/docs/extensions/reference/declarativeNetRequest/). – wOxxOm Feb 02 '22 at 21:43
  • 1
    I'm so sorry, but how would I do this with declarativeNetRequest? Would it involve making a rule set or something else I missed? – Mood Feb 03 '22 at 00:13
  • See the examples in the documentation and add a rule that removes this header. – wOxxOm Feb 03 '22 at 00:14
  • I checked the documentation, and I added a rule using what it said. It's still not working. – Mood Feb 03 '22 at 02:53
  • It's a separate problem for which you can open a new question with [MCVE](/help/mcve). – wOxxOm Feb 03 '22 at 09:45
  • 1
    It might not work if website adds strict CSP via HTML tag as extension cannot remove it to disable CSP. – Vaibhav Nigam Dec 20 '22 at 04:44
  • You can remove it via chrome.debugger API which allows patching the response body of any requests. – wOxxOm Dec 20 '22 at 08:03