Browser extensions can be confusing at the best of times, but recently we've seen that the current state of affairs is causing web store reviews to take weeks and there is evidence to show that nobody is safe from the wrath of the review teams.
Needless to say, whether you're publishing your first browser extension or already have one listed, it's worth making sure your submissions are prepared for a rigorous review.
Here's a quick run-through for how you can lock down your browser extension and increase your chance of getting your extension approved swiftly.
Timing your permissions
The fewer permissions your extension requires to run, the faster it's likely going to get through review. One of the ways you can trim down permissions without changing functionality is by only requesting additional permissions on an ad-hoc basis.
👎 Install-time permissions
The simplest approach, called "install-time permissions", involves an extension requesting, and being granted, permissions upon installation. Once installed, this allows the given extension to make use of its privileges at any time.
As you can imagine, this is a pattern that does little to restrict extensions functioning outside of their advertised feature-set. Most other ecosystems (see Android, IOS and W3) have tried to avoid or phase out this approach in favor of runtime permissions.
Consider an extension that granted install-time permissions for accessing all webpages and the microphone. Following installation, such an extension has the potential to do the following without requiring further approval:
- Read any webpage content — bank details, messages, network requests
- Manipulate any webpage content — inject adverts, political propaganda, Rick Astley videos
- Listen to any user events — see key presses (including passwords), clicks, network traffic
- Record audio at any time
Chrome install prompt for
Because permissions are granted in advance and the user has no way to regulate these permissions following installation, be prepared for meticulous reviews and publishing delays.
👍 Runtime permissions
Runtime permissions are a safer option for both users and extension developers. They work in a similar fashion to most other platforms by requesting no special permissions at install time and instead, prompt the user for additional permissions as-and-when needed.
Chrome install prompt for optional permissions
While this can take more time to implement, by using this method users can have a better idea as to when and why an extension is using any privileges. This also provides a means for the user to use a given extension with limited functionality, as opposed to the all-or-nothing case that install-time permissions offer.
The major caveat that comes with runtime permissions is the requirement that a permission request must be triggered inside of a user event handler. In other words, there is no way to programmatically trigger a permission request unless it is immediately following a user gesture.
Requesting webpage permissions
There are a few different ways a webpage can request permission to access a webpage — with some being better than others.
🥇 Active tab
For cases where a content script is required to run on the current active tab and only following a user invocation:
"permissions": ["activeTab"],
Example use of active tab permissions in an extension manifest.
Because this permission is technically always granted at runtime (by user invocation), declaring it as an install-time permission is common practice and will not result in any warnings to the user.
You might want to use this if:
- your extension can be invoked by a user action
- your extension only needs permission for the current tab
🥈 Match patterns
This is a host permission, intended for extensions where a content script is required to run on specific domains:
"permissions": [
"https://my.domain.com",
"https://*.domain.com", // Subdomain wildcard
],
// or
"optional_permissions": [
"*://my.domain.com", // Scheme wildcard (https|http|ws)
"https://my.domain.com/*" // Path wildcard"
],
Example use of scoped host permissions in an extension manifest.
You might want to use this if:
- your extension needs permission for specific known URLs
- your extension can't use activeTab
🥉 All URLs
This is the broadest host permission scope intended for extensions where a content script is required to run on all webpages without user invocation.
"permissions": ["<all_urls>"],
// or
"optional_permissions": ["<all_urls>"],
Example use of in an extension manifest.
You might want to use this if:
- your extension needs permission for all URLs
- your extension can't use activeTab
Preventing unsafe code
While reviewers will be spending a fair amount of time reviewing the code you submitted, that's not all that needs to be considered. There is likely a fair amount of code that is also included with your extension and has not been explicitly written by you (such as third-party dependencies).
Not only does your code need to be assessed for malicious content, dependencies are also an attack vector.
🛡 Content Security Policies (CSP)
Just like websites, browser extensions can make use of a Content Security Policy (CSP) to limit how code can be sourced and run in the browser.
"content_security_policy": "script-src 'self';",
Example use of a content security policy in an extension manifest.
While we haven't yet found an automated solution for injecting safe checksums into the extension manifest at build time, there is a webpack plugin to do this for webpages — an additional layer of security if your extension includes any HTML pages (such as a devtools panel).
🕵️♀️ Linting your extension
The team over at Mozilla have created a great CLI for browser extensions called web-ext. It includes a bunch of neat features for running, building, and testing your extension; and most importantly, it can lint extensions to flag vulnerabilities.
Output from running web-ext lint
From issues in the manifest to unsafe practices in your JS, this one catches a myriad of issues and is a must for anyone building a browser extension.
There's a chance that this will be used by store reviewers when assessing your extension so be sure to address any flagged issues before publishing.
Sealing the deal
For the time being, browser extension reviews are being done by humans, not an automated program. Reviewers are the number one people to please as they have the power to accept or deny your listing onto the web store, so be sure to make their life as easy as possible and get them on your side.
📘 Document the purpose
Try to document what the purpose of the extension is, and make it clear why the extension requests the permissions it does.
For example, a "dark mode" extension that accesses your webcam without explanation could trigger alarm bells. If it's explained that the webcam is used to detect ambient light, this is less likely to be the case.
🗺 How did you get there
Nobody likes reading minified code. If there is a build process to publish your extension, make sure to provide the source code and instructions on how to reproduce the built files.
Linking to the open source repo is another great way to gain trust.
🦺 Be conservative
A secure extension which uses CSPs, minimal permissions, and minimal dependencies should take less time to review.
This process isn't perfect
Even if you follow all these guidelines, there's no guarantee your project will be reviewed in a short amount of time. Manual reviews naturally take a long time and there are plenty of good reasons why some of the prior advice can't be followed.
Our very own urql Devtools is a great example of this. Like many other devtools extensions, anyone with our extension installed will have a content script run on every page they visit (i.e. install-time permissions for <all_urls>
).
Frankly, we don't want this to be the case, but the current state of browser extension permissions means it's just not possible to request permission to access a page at runtime when a user opens the devtools panel (as this does not constitute a "user gesture").
Can browser extensions be even safer in the future?
Making suggestions for browser standards is well outside of my skill-set and I'm sure there are some very smart people actively working on this.
One thing I would like to see is a continued movement towards reducing the number of browser extensions requesting permissions at install-time. The limitation in which extensions can only request permissions following a user gesture was clearly to prevent permission spam. I agree with the incentive but I suspect this decision has led to many extensions (including devtools extensions) being cornered into requesting more than permissions than they actually need.
Prevention of permission request spam in Android 10
Hopefully, in the future, we'll see a process that follows in the footsteps of other platforms that have managed to give users dynamic permission control while also preventing permission request spam.
Additional resources
- Formidable urql Devtools on GitHub
- Mozilla Review installed extensions
- Mozilla Getting started with web-ext
- Google Chrome permissions
- Google Chrome webstore policy
Credits
Special thanks to Umar Hansa (@umaar) for the peer review!
This post was made thanks to the the support of Formidable. Check out the original post here.
Top comments (0)