Load wasm module using manifest V3

4,177 views
Skip to first unread message

Giacomo Tommaso Petrucci

unread,
Jun 9, 2022, 10:17:53 AM6/9/22
to Chromium Extensions
Greetings,
I'm developing a Chromium extension using webpack and manifest version 3. I need to load a web assembly module and I've already enabled both syncWebAssembly and asyncWebAssembly inside webpack (although my understanding is that, since I'll be using the module inside a service worker, there is no way of loading it asynchronously as I can't use the import() function).
The problem is that after enabling wasm loading in webpack, I get the following error in the service worker's console:

"Uncaught (in promise) CompileError: WebAssembly.instantiateStreaming(): Wasm code generation disallowed by embedder"

Looking for a solution, I found this closed issue: LyX Document There is mentioned a special content security policy: wasm-unsafe-eval. I tried to add that to my manifest, with the only result that now in addition to the previous error I get a new one: "Unrecognized Content-Security-Policy directive 'wasm-unsafe-eval'."
Some comments in the issue say that the fix hasn't been implemented in the stable branch of Chrome yet, so I tried both Chrome-dev and Chrome canary, but I got the exact same errors on both. 

What should I do to be able to load a wasm module inside a service worker?
PS: the wasm module isn't being fetched form some server, I have it locally on my PC.

Thank you for your help,

Giacomo

Giacomo Tommaso Petrucci

unread,
Jun 9, 2022, 10:37:27 AM6/9/22
to Chromium Extensions, Giacomo Tommaso Petrucci
An update on this: I found out that I was specifing 'wasm-unsafe-eval' in the wrong place inside the CSP string. Now the error "Unrecognized Content-Security-Policy directive 'wasm-unsafe-eval'." is gone, but I till have the error "Uncaught (in promise) CompileError: WebAssembly.instantiateStreaming(): Wasm code generation disallowed by embedder".
This is how my CSP looks like now:

"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'; worker-src 'self' 'wasm-unsafe-eval';"
}

How can I fix this?

Thank you for your availability,

Giacomo

Giacomo Tommaso Petrucci

unread,
Jun 9, 2022, 11:33:36 AM6/9/22
to Chromium Extensions, Giacomo Tommaso Petrucci
Last quick update: if I try to load my extension inside Chrome canary started with the flag --enable-features=AllowWasmInMV3 , then I get the following error in a popup on the extensions page: "
'content_security_policy.extension_pages': Insecure CSP value "wasm-unsafe-eval" in directive 'worker-src'. "
What should I do?

Simon Bassu

unread,
Jun 10, 2022, 11:59:38 AM6/10/22
to Giacomo Tommaso Petrucci, Chromium Extensions

We have the same problem.
Tested with Google Chrome Canary 104.
According to 

It should be fixed.

Uncaught (in promise) EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' 'wasm-unsafe-eval'".

We've tried to add "script-src 'self' 'wasm-unsafe-eval’", with no success.

Someone?


-- 
You received this message because you are subscribed to the Google Groups "Chromium Extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extens...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-extensions/5b04a4c0-e25e-4110-ad40-04de9d44c9afn%40chromium.org.

Jackie Han

unread,
Jun 10, 2022, 12:48:00 PM6/10/22
to Simon Bassu, Giacomo Tommaso Petrucci, Chromium Extensions
I did a simple test(sample code frome MDN), below wasm code works without problem in extension page and service worker.

// manifest.json
{
  "manifest_version": 3,
  "content_security_policy": {
    "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';"
  },
}

// sw.js or extensionPage.js
var importObject = { imports: { imported_func: arg => console.log(arg) } };
WebAssembly.instantiateStreaming(fetch('simple.wasm'), importObject)
.then(obj => obj.instance.exports.exported_func());//output 42 in console



Simon Bassu

unread,
Jun 10, 2022, 1:48:58 PM6/10/22
to Jackie Han, Giacomo Tommaso Petrucci, Chromium Extensions

The example works when you load the wasm in the background service-worker, but doesn’t when you load in a content script. Even if we put the warm file in the web_accessible_resources list.

We don't have any problem with mv2

Jackie Han

unread,
Jun 10, 2022, 2:26:59 PM6/10/22
to Simon Bassu, Giacomo Tommaso Petrucci, Chromium Extensions
I just tested the content script.

// manifest.json
  "web_accessible_resources": [
    {
      "resources": [ "simple.wasm" ],
      "matches": [ "<all_urls>" ]
    }
  ],

// insert content script, that run wasm
function wasm() {

  var importObject = { imports: { imported_func: arg => console.log(arg) } };
  WebAssembly.instantiateStreaming(fetch(chrome.runtime.getURL('simple.wasm')), importObject)
  .then(obj => obj.instance.exports.exported_func());
}

async function inject(e) {
  const tabId = (await chrome.tabs.query({active: true}))[0].id;
  chrome.scripting.executeScript({
    target: {tabId},
    func: wasm
  });
}


Above code can still work in some web pages (not all web pages). Because content scripts run in web page context (not in extension context), it follows web page's CSP (not extension's CSP). For example:
1) Above code works on https://www.google.com/
2) But it doesn't work on https://github.com/ , because github's CSP limits this behavior.

Uladzimir Yankovich

unread,
Jun 11, 2022, 3:46:22 AM6/11/22
to Chromium Extensions, Jackie Han, giacomo.to...@gmail.com, Chromium Extensions, Simeon Bassu
Jackie, you are amazing as always!

Giacomo Tommaso Petrucci

unread,
Jun 15, 2022, 3:47:14 AM6/15/22
to Chromium Extensions, Jackie Han, Giacomo Tommaso Petrucci, Chromium Extensions, Simeon Bassu
Thanks this works! So in the end I was just specifying the CSP the wrong way..

Mike-O

unread,
Jul 12, 2022, 4:41:24 PM7/12/22
to Chromium Extensions, giacomo.to...@gmail.com, Jackie Han, Chromium Extensions, Simeon Bassu
It's been awhile since I logged in and looked at the WASM status. Will we finally be able to load WASM modules in MV3 if we do special things in our manifest and other rules? I hate that WASM obscures code and that's a security issue, but it speeds up processing tremendously. If WASM is not going to be supported, then it would be great if when someone downloads the extension, we can load WASM as WASM original source, and then when the plugin loads, it does a one-time compile into the WASM module and uses that module instead. And, as long as the source hash hasn't changed, it continues to load that one-time compile that it's already done. That way, you get the security of knowing what's going on in an extension under the hood, while getting the performance of WASM.

Simeon Vincent

unread,
Jul 12, 2022, 6:23:10 PM7/12/22
to Mike-O, Chromium Extensions, giacomo.to...@gmail.com, Jackie Han, Simeon Bassu
As of Chrome 102 extensions can set the wasm-unsafe-eval directive in the extension's CSP in order to load wasm in extension contexts. See Jackie's post further up in this thread for an example.

Simeon - @dotproto
Chrome Extensions DevRel


Mike-O

unread,
Jul 13, 2022, 12:46:30 AM7/13/22
to Chromium Extensions, Simeon Vincent, Chromium Extensions, giacomo.to...@gmail.com, Jackie Han, Simeon Bassu, Mike-O
1. Can extensions built with  wasm-unsafe-eval   be used in production, allowed in the Chrome Store, or only as Developer Mode extensions?

2. What do end users see as far as a permission prompt with this?

Simeon Vincent

unread,
Jul 13, 2022, 12:54:38 AM7/13/22
to Mike-O, Chromium Extensions, giacomo.to...@gmail.com, Jackie Han, Simeon Bassu
1. Can extensions built with  wasm-unsafe-eval be used in production, allowed in the Chrome Store, or only as Developer Mode extensions?

Yes, wasm-unsafe-eval can be used in production. Yes, you can publish an extension that uses wasm-unsafe-eval to the Chrome Web Store. No, this capability is not limited to unpacked extensions loaded in developer mode.

2. What do end users see as far as a permission prompt with this?

Extension content security policy rules do not interact with the extension platform's permissions system. As such, end users will not see a warning at installation time or have to explicitly grant the extension permission to use Wasm.

Simeon - @dotproto
Chrome Extensions DevRel

Mike-O

unread,
Jul 13, 2022, 1:05:07 AM7/13/22
to Chromium Extensions, Simeon Vincent, Chromium Extensions, giacomo.to...@gmail.com, Jackie Han, Simeon Bassu, Mike-O
Interesting. I'm pleased with this new feature. However, I have to ask why the "about-face" from the original MV3 team on this? Weren't they concerned about security implications of compiled WASM code limiting the code transparency of MV3 extensions?

"A key security improvement in Manifest V3 is that extensions can't load remote code like JavaScript or Wasm files. This lets us more reliably and efficiently review the safe behavior of extensions when they're submitted to the Chrome Web Store. Specifically, all logic must be included in the extension's package."

An alternative idea to consider could be that uncompiled WASM code could be downloaded with extension download, gets compiled on installation, and then if the uncompiled source hash never changes, then the extension continues to use the compiled module. That way, you get some kind of code transparency on what is going on inside the WASM module, yet get the speed of compiled WASM.


Jackie Han

unread,
Jul 13, 2022, 8:29:58 AM7/13/22
to Mike-O, Chromium Extensions, Simeon Vincent, giacomo.to...@gmail.com, Simeon Bassu
An alternative idea to consider could be that uncompiled WASM code could be downloaded with extension download, gets compiled on installation ……

Browser can run WASM, but it can't compile it. There are different languages, so they need different compiler/toolchain.

Simeon Vincent

unread,
Jul 13, 2022, 1:14:16 PM7/13/22
to Jackie Han, Mike-O, Chromium Extensions, giacomo.to...@gmail.com, Simeon Bassu
However, I have to ask why the "about-face" from the original MV3 team on this? 

If you're only considering what is technically possible or what is allowed by an extension's content security policy (CSP), this may seem like a reversal, but from the start of the Manifest V3 effort we've approached limiting an extension's ability to execute remote code through a combination of extension platform changes and Chrome Web Store policy changes. 

On the policy side, we added Additional requirements for Manifest V3 to the Developer Program Policies in early 2022. This change requires that Manifest V3 extensions include all of the code they execute in the extension's bundle. While this policy defines what we allow on the Chrome Web Store, it doesn't directly help steer developers in the right direction; that's where platform changes come in.

On the technical side, one of the changes we pursued to prevent extensions from executing untrusted code is a limitation on what CSP directives and values extensions can set. For example, we can prevent extensions from calling eval() in extension contexts by not allowing extensions to use unsafe-eval in script-src. The problem here, though, is that over the past few years the way CSP and Wasm interact has been a bit of a moving target.

Historically, unsafe-eval was also used to control Wasm execution in browsers. In order to expose Wasm to Chrome extensions and apps, Chrome implemented the non-standard value "wasm-eval". Later, as the Wasm Working Group began to align on the introduction of "wasm-unsafe-eval" Chrome added support for that value. At the time we (extensions folks) thought that wasm-unsafe-eval was meant to be the Wasm equivalent of unsafe-eval and so didn't expose it to extensions. We were anticipating the introduction of another value or new directive that would allow us to restrict Wasm execution to sources loaded form the extension's origin, but unfortunately, that kind of control via CSP is still an unsolved problem. This created a situation where Manifest V2 extensions could use bundled Wasm but Manifest V3 extensions could not. Ultimately we decided it was best to allow extensions to set wasm-unsafe-eval and to adopt new CSP directives/values when they are introduced.

Simeon - @dotproto
Chrome Extensions DevRel

Reply all
Reply to author
Forward
0 new messages