chrome.runtime.onMessage is undefined in MV3 content script

1,601 views
Skip to first unread message

Darin Dimitrov

unread,
Mar 29, 2023, 11:28:31 AM3/29/23
to Chromium Extensions
I am trying to migrate an extension to manifest V3 and I encountered an issue. 

The service worker injects a content script into the active tab:

chrome.tabs.query({ active: true, currentWindow: true}, tabs => {
    chrome.scripting.executeScript({
        world: 'MAIN',
        target: { tabId: tabs[0].id },
        func: () => {
            console.log(chrome.runtime)
            console.log(chrome.runtime.onMessage)
        }
    }, () => { });
});


Inside the content script chrome.runtime.onMessage is undefined whereas other properties of chrome.runtime are present. I need to subscribe to events inside the content script.

Am I missing something? Do I need some special permission in the manifest to be able to access this property?

Here's an excerpt from the manifest:

"permissions": [
    "activeTab",
    "scripting"
],
"host_permissions": [
    "<all_urls>"
]


In MV2 I had <all_urls> added to the permissions section but in MV3 got a warning that this should be moved to host_permissions and I did so.

Patrick Kettner

unread,
Mar 29, 2023, 7:01:39 PM3/29/23
to Darin Dimitrov, Chromium Extensions
This is working as intended. Scripts that are injected via chrome.scripting do not have access to onMessage.  You can access chrome.runtime.onMessage via content-script, however.

--
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/ce8daa88-2d47-453d-9a85-5164b0312498n%40chromium.org.

wOxxOm

unread,
Mar 29, 2023, 8:25:22 PM3/29/23
to Chromium Extensions, Patrick Kettner, Chromium Extensions, Darin Dimitrov
> This is working as intended. Scripts that are injected via chrome.scripting do not have access to onMessage.  You can access chrome.runtime.onMessage via content-script, however.

While this is intended, but not for the reason stated in the quote, which is actually wrong because chrome.scripting by itself doesn't preclude the use of onMessage.

The actual reason for the observed behavior is that the code is explicitly injected by the author in MAIN world, i.e. the normal JS context of the page where all the web page scripts run. The `chrome` API is exposed for contents scripts only in the default ISOLATED world which is used by default when you don't specify `world` parameter.

The MAIN world (the web page world) sees `chrome` only when there is at least one extension that has this site listed in externally_connectable in its manifest.json.

Note that code you inject in the MAIN world can be hijacked and the data may be intercepted by any other web page script (or by another extension's script) that already ran in the page and spoofed global objects like Object.prototype, Array.prototype, Function.prototype. Never inject in the MAIN world your entire content script. Only inject a small portion that needs to access some JS object in the MAIN world, and never trust this data fully i.e. sanitize/verify it.

Chrome team has made a mistake by naming such MAIN-world scripts "content scripts" so this kind of confusion is already in the process of becoming a widespread problem.

Simeon Vincent

unread,
Mar 30, 2023, 3:21:31 AM3/30/23
to wOxxOm, Chromium Extensions, Patrick Kettner, Darin Dimitrov
Solid recommendations from wOxxOm around sanitizing data in untrusted scripts. 

Chrome team has made a mistake by naming such MAIN-world scripts "content scripts" so this kind of confusion is already in the process of becoming a widespread problem.

I agree that the terminology isn't ideal, but I don't quite follow your comment that it's "already in the process of becoming a widespread problem." This problem existed in Manifest V2 as well: appending a script tag to the host page would inject extension content into the page's main execution environment – a main world content script.

How would you rather refer to this functionality? How would you change the API to better set developer expectations?

Simeon - @dotproto

wOxxOm

unread,
Mar 30, 2023, 5:19:12 AM3/30/23
to Chromium Extensions, Simeon Vincent, Chromium Extensions, Patrick Kettner, Darin Dimitrov, wOxxOm
>  I agree that the terminology isn't ideal, but I don't quite follow your comment that it's "already in the process of becoming a widespread problem."

That's because I start seeing it in questions on stackoverflow.com where I answered/commented on thousands upon thousands of  questions in the extensions tag for ~8 years. Judging by https://github.com/w3c/webextensions/issues/313 all extension teams (Chrome, Firefox and Safari) don't understand the danger of the confusion they sow by using this name.

>  This problem existed in Manifest V2 as well:

No, there was no such problem because the extensions platform didn't name such scripts. The ability to run in the MAIN world by creating a DOM script element wasn't documented so most developers didn't even know it was possible in MV2 unless they stumbled on the info by searching for symptoms of not being able to access some JS variable/method from a content script. I redirect such questions each month to the canonical answer by Rob Wu. The only API that could inject in the MAIN world directly was chrome.devtools.inspectedPage.eval and it only described the effects: "execute JavaScript code in the context of the inspected page".

> How would you rather refer to this functionality? How would you change the API to better set developer expectations?

For ~10 years that this functionality has been used (MV2 made it necessary) it didn't have one established name. There was "DOM-injected script", "page-level script", "injected page script", "injected script". All of these are imprecise, but still better than "content script". I don't know what is the best name. For the time being I think I'll call such scripts "MAIN-world scripts".

Simeon Vincent

unread,
Mar 30, 2023, 1:34:22 PM3/30/23
to wOxxOm, Chromium Extensions, Patrick Kettner, Darin Dimitrov
Thanks for the clarification and link to #313, wOxxOm. I think I understand the problem now, but I confess I'm too tired at the moment to grapple with how to fix it.

Simeon - @dotproto

wOxxOm

unread,
Mar 30, 2023, 1:46:10 PM3/30/23
to Chromium Extensions, Simeon Vincent, Chromium Extensions, Patrick Kettner, Darin Dimitrov, wOxxOm
Renaming is probably out of the question at this stage, but maybe a practical solution would be to name them "unsafe content scripts", linking the term to an article/section that describes how easy it is for a page script to intercept/spoof/hijack the data via global prototypes.
Reply all
Reply to author
Forward
0 new messages