Deal with remote hosted code violations

Remotely hosted code, or RHC, is what the Chrome Web Store calls anything thatis executed by the browser that is loaded from someplace other than theextension's own files. Things like JavaScript and WASM. Itdoes not includedata or things like JSON or CSS.

Why is RHC no longer allowed?

With Manifest V3 extensions now need to bundleall code they are using insidethe extension itself. In the past, you could dynamically inject script tags fromany URL on the web.

I was told my extension has RHC. What's going on?

If your extension was rejected during review with aBlue Argon error, thenour reviewers believe that your extension is using remotely hosted code. This isusually the result of an extension trying to add a script tag with a remoteresource (i.e. from the open web, rather than the files included in theextension), orfetching a resource to execute directly.

How to spot RHC

Spotting RHC isn't particularly difficult once you know what to look for. First,check for the strings "http://" or "https://" in your project. If you have anRHC violation, then you would likely be able to locate them by finding that. Ifyou have a full build system, or use dependencies fromnpm or other thirdparty sources, make sure you are searching thecompiled version of the code,since that is what is being evaluated by the store. If you are still unable tofind the problem, then the next step is to contactOne Stop Support. Theywill be able to outline the specific violations, and what is needed to get theextension published as soon as possible.

What to do if a library is requesting the code

Regardless of where the code comes from, it is not allowed to have RHC. Thisincludes code you didn't author, but just happen to use as a dependency in yourproject.Some developers usingFirebase had this issue when remotecode was being included for use inFirebase Auth. Even though this was afirst party (i.e. Google owned) library, no exception is given for RHC. You needto configure the code to either remove the RHC or update your poject to notinclude the code to begin with. If you hit an issue where it isn'tyour codethat is loading RHC, but a library that you are using, then the best course ofaction is to contact the library's author. Let them know that this is happening,and ask for either a workaround or code updates to remove it.

What if you can't wait for a library update

Some libraries will ship an update almost immediately after being notified, butothers may be abandoned or take time to address the issue. Depending onwhatis happening in the specific violation, you may not need to wait for them tomove to be unblocked and complete a successful review. There are a number ofoptions available to get back up and running quickly.

Audit the code

Are youcertain that the code that is causing the request is needed? If it canjust be deleted, or a library that is causing it can be removed, then deletethat code, and the job is done.

Alternatively, is there another library that offers the same features? Trycheckingnpmjs.com, GitHub, or other sites for other options that fulfillthe same use cases.

Tree shaking

If the code causing the RHC violation isn't actually being used, then it may beable to be automatically deleted by tooling. Modern build tools likewebpack,Rollup, andVite (just to name a few) have a featurecalledtree-shaking. Once enabled on your build system, tree shakingshould remove any unused code paths. This can mean that you not only have a morecompliant version of your code, but a leaner and faster one too! It is importantto note that not all libraries are able to be tree shaken, but many are. Sometools, like Rollup and Vite, have tree-shaking enabled by default. webpackneeds to be configured for it to be enabled. If you aren't using a buildsystem as a part of your extension, butare using code libraries, then you arereally encouraged to investigate adding a build tool to your workflow. Buildtools help you write safer, more reliable and more maintainable projects.

The specifics of how to implement treeshaking depend on your specific project.But to take a simple example with Rollup, you can add treeshaking just bycompiling your project code. For example, if you have a file that only logs intoFirebase Auth, called main.js:

import{GoogleAuthProvider,initializeAuth}from"firebase/auth";chrome.identity.getAuthToken({'interactive':true},async(token)=>{constcredential=GoogleAuthProvider.credential(null,token);try{constapp=initializeApp({...});constauth=initializeAuth(app,{popupRedirectResolver:undefined,persistence:indexDBLocalPersistence});const{user}=awaitauth.signInWithCredential(credential)console.log(user)}catch(e){console.error(error);}});

Then all you would need to do is tell Rollup the input file, a plugin needed toload node files@rollup/plugin-node-resolve, and the name of the outputfile it is generating.

npxrollup--inputmain.js--plugin'@rollup/plugin-node-resolve'--filecompiled.js

Running that command in a terminal window, you will receive a generated versionof ourmain.js file, all compiled into a single file namedcompiled.js.

Rollup can be simple, but it is alsovery configurable. You can add all kindsof complex logic and configuration, just check out theirdocumentation.Adding build tooling like this will result in a smaller, more efficient code,and in this case, fixes our remote hosted code issue.

Automatically editing files

An increasingly common way that remotely hosted code can enter your codebase isas a subdepenency of a library you are including. If libraryX wants toimport libraryY from a CDN, then you will still need to update it to makeit load from a local source. With modern build systems, you can trivially createplugins to extract a remote reference, and inline it directly into your code.

That would mean that given code that looks like this:

importmomentfrom"https://unpkg.com/moment@2.29.4/moment.js"console.log(moment())

You could make a small rollup plugin.

import{existsSync}from'fs';importfetchfrom'node-fetch';exportdefault{plugins:[{load:asyncfunctiontransform(id,options,outputOptions){// this code runs over all of out javascript, so we check every import// to see if it resolves as a local file, if that fails, we grab it from// the network using fetch, and return the contents of that file directly inlineif(!existsSync(id)){constresponse=awaitfetch(id);constcode=awaitresponse.text();returncode}returnnull}}]};

Once you run the build with the new plugin, every remoteimport URL isdiscovered regardless of whether or not it was our code, a subdependency,subsubdependecy, or anywhere else.

npxrollup--inputmain.js--config./rollup.config.mjs--filecompiled.js

Manually editing files

The simplest option is just to delete the code that is causing the RHC. Open inyour text editor of choice, and delete the violating lines. This generallyisnot that advisable, because it is brittle and could be forgotten. It makesmaintaining your project harder when a file called "library.min.js" isn'tactually library.min.js. Instead of editing the raw files, a slightly moremaintainable option is to use a tool likepatch-package. This is a superpowerful option that lets you savemodifications to a file, rather than thefile itself. It is built onpatch files, the same sort of thing thatpowers version control systems likeGit orSubversion. You just needto manually modify the violating code, save the diff file, and configurepatch-package with the changes you want to apply. You can read a full tutorialon theproject's readme. If you are patching a project, wereallyencourage you to reach out to the project to request that changes be madeupstream. While patch-package makes managing patches a lot easier, havingnothing to patch is even better.

What to do if the code isn't being used

As codebases grow, dependencies (or dependency of a dependency, or dependencyof…) can keep code paths that are no longerbeing used. If one of those sectionsincludes code to load or execute RHC, then itwill have to be removed. Itdoesn't matter if it is dead or unused. If it isn't being used it should beremoved, either by treeshaking, or patching the library to remove it.

Is thereany workaround?

Generally speaking, no. RHC is not allowed. There is, however, a small number ofcases where itis allowed. These are almost always cases where it isimpossible for any other option.

User Scripts API

User Scripts are small code snippets that are usually supplied by theuser, intended for User Script managers likeTamperMonkey andViolentmonkey. It is not possible for these managers to bundle code thatis written by users, so the User Script API exposes a way to execute codeprovided by the user. Thisis not a substitute forchrome.scripting.executeScript, or other code execution environments.Users must enabledeveloper mode to execute anything. If the Chrome WebStore review team thinks that this is being used in a manner other than it isintended for (i.e. code provided by the user), it may be rejected or it'slisting taken down from the store.

chrome.debugger

Thechrome.debugger API gives extensions the ability to interact withtheChrome Devtools Protocol. This is the same protocol that is used forChrome's Devtools, and anamazing number of other tools. With it, anextension can request and execute remote code. Just like user scripts, it is nota substitute for chrome.scripting, and has a much more notable user experience.While it is being used, the user will see a warning bar at the top of thewindow. If the banner is closed or dismissed, the debugging session will beterminated.

Screenshot of the address bar in Chrome that has the message 'Debugger Extension started debugging this browser'
Screenshot of the address bar in Chrome that has the message 'Debugger Extension started debugging this browser'

Sandboxed iframes

If you need to evaluate a string as code, and are in a DOM environment (e.g. acontent script, as opposed to an extension service worker), then another optionis to use asandboxed iframe. Extensions don't support things likeeval() by default as a safety precaution. Malicious code could put user safetyand security at risk. But when the code is only executed in a known safeenvironment, like an iframe that has been sandboxed from the rest of the web,then those risks are greatly reduced. Within this context, the Content SecurityPolicy that blocks the usage of eval can be lifted, allowing you to run anyvalid JavaScript code.

If you have a use case that isn't covered, feel free to reach out to the teamusing thechromium-extensions mailing list to get feedback, or open a newticket to request guidance fromOne Stop Support

What to do if you disagree with a verdict

Enforcing policies can be nuanced and review involves manual input, which meansthe Chrome Web Store team may sometimes agree to change a review decision. Ifyou believe that a mistake was made in review, you can appeal the rejectionusingOne Stop Support

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2023-12-13 UTC.