Openness and security: a balancing act for the add-ons ecosystem

Add-ons offer a powerful way for people to customize their web experience in Firefox. From content blocking and media enhancement to productivity tooling, add-ons allow third-party developers to create, remix, and share new products and experiences for the web. The same extensibility that allows developers to create utility and delight in Firefox, however, can also be used by malicious actors to harvest and sell user data.

With an ecosystem of 20,000+ extensions hosted on addons.mozilla.org (AMO), hundreds of thousands of self-distributed extensions, and millions of users around the world, finding the right balance between openness and security is a key challenge for our small team. Developers need to feel supported on our platform, and users need to feel safe installing add-ons, so we continually make adjustments to balance these interests.

Adapting our review model

Prior to the adoption of a new extensions API in 2017, buggy or malicious add-ons could take nearly full control of Firefox, and in some cases, a user’s device. Because these extensions could do so much potential damage, all add-ons hosted on addons.mozilla.org (AMO) had to pass human review before they could be released to users. This led to long delays where developers sometimes waited weeks, if not months, for their submissions to be reviewed. In some cases, developers waited months for an add-on to be reviewed, only to have it rejected.

The transition to the new extensions API greatly limited the potential for add-ons to cause damage. Reducing the attack surface enabled us to move to a post-submission review model, where extensions undergo automated checks and are prioritized for human review based on certain risk factors before becoming available, usually within a few hours. All add-ons are subject to human review at any time after publication.

Human reviews are still necessary

Since the transition to a post-submission review model, we have continued to make adjustments to our products, systems, and processes to maintain a balance between user safety and developer support. While we’ve made gains in new mechanisms to combat malicious activity, human review remains the most reliable method for verifying the safety of an add-on because of the complex and contextual nature of add-on code written in JavaScript.

However, human code review is a resource-intensive activity. As we weighed our options for how to keep add-ons safe for users in 2019, it became clear that we only possessed the resources to guarantee human reviews for a small number of extensions. Because we already had an editorial program in place for identifying and featuring add-ons, it made sense to build a trusted add-on program off past curatorial efforts. This became the Recommended Extensions program.

Currently, we human-review every version of each of our 100+ Recommended Extensions before publication. Beyond that, our limited review resources are focused on monitoring and stamping out malicious activity that may be lurking in our ecosystem. For a sense of scale, AMO receives 20,000+ new version submissions per month.

Since we can only guarantee human-review for all versions of Recommended Extensions, AMO applies a warning message to the listing pages of all non-Recommended extensions. The intention of this message is to let users know that since a non-Recommended extension may not have been reviewed by a human, we can’t guarantee it’s safe.

Developer feedback and future plans

We’ve heard feedback from developers whose add-ons are not in the Recommended program that they are concerned the warning message can discourage users from installing their add-ons. Some have asked whether it’s possible to request human reviews for their add-ons so they can be badged as safe to install. We are exploring ways to better support these developers and provide more discovery opportunities for them.

During the remainder of 2020, we will experiment with new programs to address these issues and help more extensions become successful. Please stay tuned to this blog for updates on the upcoming experiments and opportunities for participation, and head to our community forum with any questions or feedback.

Extensions in Firefox 79

We have a little more news this release: a new API method, a reminder about a recently announced change, a preview of some things to come, and a few interesting improvements. Let’s get started!

Warming up tabs

To optimize resource usage, render information on inactive tabs is discarded. When Firefox anticipates that a tab will be activated, the tab is “warmed up”. Switching to it then feels much more instantaneous. With the new tabs.warmup function, tab manager extensions will be able to benefit from the same perceived performance improvements. Note this API does not work on discarded tabs and does not need to be called immediately prior to switching tabs. It is merely a performance improvement when the tab switch can be anticipated, such as when hovering over a button that when clicked would switch to the tab.

Changes to storage.sync

We’ve blogged about this recently, but given this is part of Firefox 79 I wanted to make sure to remind you about the storage.sync changes we’ve been working on. Storage quotas for the storage.sync API are now being enforced as part of backend changes we’ve introduced for better scalability and performance.

There is no immediate action required if you don’t use the storage.sync API or are only storing small amounts of data. We encourage you to make your code resilient while your storage needs grow by checking for quota errors. Also, if you are getting support requests from users related to stored preferences you may want to keep this change in mind and support them in filing a bug as necessary.

For more information and how to file a bug in case you come across issues with this change, please see the blog post.

Firefox site isolation coming later this year

The Firefox platform team has been working on a new security architecture that isolates sites from each other, down to separating cross-origin iframes from the tab’s process. This new model, nicknamed Fission, is currently available for opt-in testing in Nightly. The platform team is planning to begin roll-out to Nightly and Beta users later this year.

So far, we have identified two changes with Fission enabled that will impact extensions:

  • Content scripts injecting extension iframes (from a moz-extension:// url) and accessing them directly via the contentWindow property will be incompatible with Fission, since that iframe will run in a different process. The recommended pattern, as always, is to use postMessage and extension messaging instead.
  • The synchronous canvas drawWindow API will be deprecated, since it’s unable to draw out-of-process iframes. You should switch to the captureTab method, which we are looking to extend with more functionality to provide a sufficient replacement.

If you are the developer of an extension that uses one of these features, we recommend that you update your extension in the coming months to avoid potential breakages.

We’re working to make the transition to Fission as smooth as possible for users and extension developers, so we need your help: please test your extensions with Fission enabled, and report any issues on Bugzilla as blocking the fission-webext meta bug. If you need help or have any questions, come find us on our community forum or Matrix.

We will continue to monitor changes that will require add-ons to be updated. We encourage you to subscribe to our blog to stay up to date on the latest developments. If more changes to add-ons are necessary we will reach out to developers individually or announce the changes here.

Miscellaneous

  • Extensions can use webRequest listeners to observe their own requests initiated by the downloads API.
  • The tabs.duplicate API now makes the tab active before resolving the promise, for parity with Chrome.
  • Disabling and re-enabling a WebExtension which provides a default search engine now correctly sets the engine as default again.

Special thanks in this release goes to community members Myeongjun Go, Sonia Singla, Deepika Karanji, Harsh Arora, and my friends at Mozilla that have put a lot of effort into making Firefox 79 successful. Also a special thanks to the Fission team for supporting us through the changes to the extension architecture. Stay tuned for next time!

Changes to storage.sync in Firefox 79

Firefox 79, which will be released on July 28, includes changes to the storage.sync area. Items that extensions store in this area are automatically synced to all devices signed in to the same Firefox Account, similar to how Firefox Sync handles bookmarks and passwords. The storage.sync area has been ported to a new Rust-based implementation, allowing extension storage to share the same infrastructure and backend used by Firefox Sync.

Extension data that had been stored locally in existing profiles will automatically migrate the first time an installed extension tries to access storage.sync data in Firefox 79. After the migration, the data will be stored locally in a new storage-sync2.sqlite file in the profile directory.

If you are the developer of an extension that syncs extension storage, you should be aware that the new implementation now enforces client-side quota limits. This means that:

  • You can make a call using storage.sync.GetBytesInUse to estimate how much data your extension is storing locally over the limit.
  • If your extension previously stored data above quota limits, all that data will be migrated and available to your extension, and will be synced. However, attempting to add new data will fail.
  • If your extension tries to store data above quota limits, the storage.sync API call will raise an error. However, the extension should still successfully retrieve existing data.

We encourage you to use the Firefox Beta channel to test all extension features that use the storage.sync API to see how they behave if the client-side storage quota is exceeded before Firefox 79 is released. If you notice any regressions, please check your about:config preferences to ensure that webextensions.storage.sync.kinto is set to false and then file a bug. We do not recommend flipping this preference to true as doing so may result in data loss.

If your users report that their extension data does not sync after they upgrade to Firefox 79, please also file a bug. This is likely related to the storage.sync data migration.

Please let us know if there are any questions on our developer community forum.

Additional JavaScript syntax support in add-on developer tools

When an add-on is submitted to Firefox for validation, the add-ons linter checks its code and displays relevant errors, warnings, or friendly messages for the developer to review. JavaScript is constantly evolving, and when the linter lags behind the language, developers may see syntax errors for code that is generally considered acceptable. These errors block developers from getting their add-on signed or listed on addons.mozilla.org.

Example of JavaScript syntax error

On July 2, the linter was updated from ESLint 5.16 to ESLint 7.3 for JavaScript validation. This upgrades linter support to most ECMAScript 2020 syntax, including features like optional chaining, BigInt, and dynamic imports. As a quick note, the linter is still slightly behind what Firefox allows. We will post again in this blog the next time we make an update.

Want to help us keep the linter up-to-date? We welcome code contributions and encourage developers to report bugs found in our validation process.

New Extensions in Firefox for Android Nightly (Previously Firefox Preview)

Firefox for Android Nightly (formerly known as Firefox Preview) is a sneak peek of the new Firefox for Android experience. The browser is being rebuilt based on GeckoView, an embeddable component for Android, and we are continuing to gradually roll out extension support.

Including the add-ons from our last announcement, there are currently nine Recommended Extensions available to users. The latest three additions are in Firefox for Android Nightly and will be available on Firefox for Android Beta soon:

Decentraleyes prevents your mobile device from making requests to content delivery networks (i.e. advertisers), and instead provides local copies of common libraries. In addition to the benefit of increased privacy, Decentraleyes also reduces bandwidth usage—a huge benefit in the mobile space.

Privacy Possum has a unique approach to dealing with trackers. Instead of playing along with the cat and mouse game of removing trackers, it falsifies the information trackers used to create a profile of you, in addition to other anti-tracking techniques.

Youtube High Definition gives you more control over how videos are displayed on Youtube. You have the opportunity to set your preferred visual quality option and have it shine on your high-DPI device, or use a lower quality to save bandwidth.If you have more questions on extensions in Firefox for Android Nightly, please check out our FAQ. We will be posting further updates about our future plans on this blog.

Extensions in Firefox 78

In Firefox 78, we’ve done a lot of the changes under the hood. This includes preparation for changes coming up in Firefox 79, improvements to our tests, and improvements to make our code more resilient. There are three things I’d like to highlight for this release:

  • When using proxy.onRequest, a filter that limits based on tab ID or window ID is now correctly applied. We’ve also greatly improved the performance of these filters. This could be useful for add-ons that want to provide proxy functionality in just one window.
  • Clicking within the context menu from the “all tabs” dropdown now passes the appropriate tab object. In the past, the active tab was erroneously passed.
  • When using downloads.download with the saveAs option set to true, the recently used directory is now remembered on a per-extension basis. For example, a user of a video downloader would benefit from not having to navigate to their videos folder every time the extension offers a file to download.

These and other changes were brought to you by Atique Ahmed Ziad, Tom Schuster, Mark Smith, as well as various teams at Mozilla. A big thanks to everyone involved in the subtle but important changes to WebExtensions in Firefox.

Friend of Add-ons: Juraj Mäsiar

Our newest Friend of Add-ons is Juraj Mäsiar! Juraj is the developer of several extensions for Firefox, including Scroll Anywhere, which is part of our Recommended Extensions program. He is also a frequent contributor on our community forums, where he offers friendly advice and input for extension developers looking for help.

Juraj first started building extensions for Firefox in 2016 during a quiet weekend trip to his hometown. The transition to the WebExtensions API was less than a year away, and developers were starting to discuss their migration plans. After discovering many of his favorite extensions weren’t going to port to the new API, Juraj decided to try the migration process himself to give a few extensions a second life.  “I was surprised to see it’s just normal JavaScript, HTML and CSS — things I already knew,” he says. “I put some code together and just a few moments later I had a working prototype of my ScrollAnywhere add-on. It was amazing!”

Juraj immersed himself in exploring the WebExtensions API and developing extensions for Firefox. It wasn’t always a smooth process, and he’s eager to share some tips and tricks to make the development experience easier and more efficient. “Split your code to ES6 modules. Share common code between your add-ons — you can use `git submodule` for that. Automate whatever can be automated. If you don’t know how, spend the time learning how to automate it instead of doing it manually,” he advises. Developers can also save energy by not reinventing the wheel. “If you need a build script, use webpack. Don’t build your own DOM handling library. If you need complex UI, use existing libraries like Vue.js.”

Juraj recommends staying active, saying. “Doing enough sport every day will keep your mind fresh and ready for new challenges.” He stays active by playing VR games and rollerblading.

Currently, Juraj is experimenting with the CryptoAPI and testing it with a new extension that will encrypt user notes and synchronize them with Firefox Sync. The goal is to create a secure extension that can be used to store sensitive material, like a server configuration or a home wifi password.

On behalf of the Add-ons Team, thank you for all of your wonderful contributions to our community, Juraj!

If you are interested in getting involved with the add-ons community, please take a look at our current contribution opportunities.

Recommended extensions — recent additions

When the Recommended Extensions program debuted last year, it listed about 60 extensions. Today the program has grown to just over a hundred as we continue to evaluate new nominations and carefully grow the list. The curated collection grows slowly because one of the program’s goals is to cultivate a fairly fixed list of content so users can feel confident the Recommended extensions they install will be monitored for safety and security for the foreseeable future.

Here are some of the more exciting recent additions to the program…

DuckDuckGo Privacy Essentials provides a slew of great privacy features, like advanced ad tracker and search protection, encryption enforcement, and more.

Read Aloud: Text to Speech converts any web page text (even PDF’s) to audio. This can be a very useful extension for everyone from folks with eyesight or reading issues to someone who just wants their web content narrated to them while their eyes roam elsewhere.

SponsorBlock addresses the nuisance of this newer, more intrusive type of video advertising.

SponsorBlock for YouTube is one of the more original content blockers we’ve seen in a while. Leveraging crowdsourced data, the extension skips those interruptive sponsored content segments of YouTube clips.

Metastream Remote has been extremely valuable to many of us during pandemic related home confinement. It allows you to host streaming video watch parties with friends. Metastream will work with any video streaming platform, so long as the video has a URL (in the case of paid platforms like Netflix, Hulu, or Disney+, they too will work provided all watch party participants have their own accounts).

Cookie AutoDelete summarizes its utility right in the title. This simple but powerful extension will automatically delete your cookies from closed tabs. Customization features include whitelist support and informative visibility into the number of cookies used on any given site.

AdGuard AdBlocker is a popular and highly respected content blocker that works to block all ads—banner, video, pop-ups, text ads—all of it. You may also notice the nice side benefit of faster page loads, since AdGuard prohibits so much content you didn’t want anyway.

If you’re the creator of an extension you feel would make a strong candidate for the Recommended program, or even if you’re just a huge fan of an extension you think merits consideration, please submit nominations to amo-featured [at] mozilla [dot] org. Due to the high volume of submissions we receive, please understand we’re unable to respond to every inquiry.

Improvements to Statistics Processing on AMO

We’re revamping the statistics we make available to add-on developers on addons.mozilla.org (AMO).

These stats are aggregated from add-on update logs and don’t include any personally identifiable user data. They give developers information about user adoption, general demographics, and other insights that might help them make changes and improvements.

The current system is costly to run, and glitches in the data have been a long-standing recurring issue. We are addressing these issues by changing the data source, which will improve reliability and reduce processing costs.

Usage Statistics

Until now, add-on usage statistics have been based on add-on updates. Firefox checks AMO daily for updates for add-ons that are hosted there (self-distributed add-ons generally check for updates on a server specified by the developer). The server logs for these update requests are aggregated and used to calculate the user counts shown on add-on pages on AMO. They also power a statistics dashboard for developers that breaks down the usage data by language, platform, application, etc.

Stats dashboard example

Stats dashboard showing new version adoption for uBlock Origin

In a few weeks, we will stop using the daily pings as the data source for usage statistics. The new statistics will be based on Firefox telemetry data. As with the current stats, all data is aggregated and no personally identifiable user data is shared with developers.

The data shown on AMO and shared with developers will be essentially the same, but the move to telemetry means that the numbers will change a little. Firefox users can opt out of sending telemetry data, and the way they are counted is different. Our current stats system counts distinct users by IP address, while telemetry uses a per-profile ID. For most add-ons you should expect usage totals to be lower, but usage trends and fluctuations should be nearly identical.

Telemetry data will enable us to show data for add-on versions that are not listed on AMO, so all developers will now be able to analyze their add-on usage stats, regardless of how the add-on is distributed. This also means some add-ons will have higher usage numbers, since the average will be calculated including both AMO-hosted and self-hosted versions.

Other changes that will happen due to this update:

  • The dashboards will only show data for enabled installs. There won’t be a breakdown of usage by add-on status anymore.
  • A breakdown of usage by country will be added.
  • Usage data for our current Firefox for Android browser (also known as Fennec) isn’t included. We’re working on adding data for our next mobile browser (Fenix), currently in development.
  • It won’t be possible to make your statistics dashboard publicly available anymore. Dashboards will only be accessible to add-on developers and admins, starting on June 11. If you are a member of a team that maintains an add-on and you need to access its stats dashboard, please ask your team to add you as an author in the Manage Authors & License page on AMO. The Listed property can be checked off so you don’t show up in the add-on’s public listing page.

We will begin gradually rolling out the new dashboard on June 11. During the rollout, a fraction of add-on dashboards will default to show the new data, but they will also have a link to access the old data. We expect to complete the rollout and discontinue the old dashboards on July 9. If you want to export any of your old stats, make sure you do it before then.

Download Statistics

We plan to make a similar overhaul to download statistics in the coming months. For now they will remain the same. You should expect an announcement around August, when we are closer to switching over to the new download data.

Extensions in Firefox 77

Firefox 77 is loaded with great improvements for the WebExtensions API. These additions to the API will help you provide a great experience for your users.

Optional Permissions

Since Firefox 57, users have been able to see what permissions an extension wants to access during the installation process.  The addition of any new permissions to the extension triggers another notification that users must accept during the extension’s next update.  If they don’t, they won’t receive the updated version.

These notifications were intended to provide transparency about what extensions can do and help users make informed decisions about whether they should complete the installation process. However, we’ve seen that users can feel overwhelmed by repeated prompts. Worse, failure to see and accept new permissions requests for updated versions can leave users stranded on older versions.

We’re addressing this with optional permissions.  First, we have made a number of permissions optional. Optional permissions don’t trigger a permission prompt for users during installation or when the extension updates. It also means that users have less of a chance of becoming stranded.

If you use the following permissions, please feel welcome to move them from the permissions manifest.json key to the optional_permissions key:

  • management
  • devtools
  • browsingData
  • pkcs11
  • proxy
  • session

Second, we’re encouraging developers who use optional permissions to request them at runtime. When you use optional permissions with the permissions.request API, permission requests will be triggered when permissions are needed for a feature. Users can then see which permissions are being requested in context of using the extension. For more information, please see our guide on requesting permissions at runtime.

As an added bonus, we’ve also implemented the permissions.onAdded and permissions.onRemoved events, allowing you to react to permissions being granted or revoked.

Merging CSP headers

Users who have multiple add-ons installed that modify the content security policy headers of requests may have been seeing their add-ons behave erratically and will likely blame the add-on(s) for not working. Luckily, we now properly merge the CSP headers when two add-ons modify them via webRequest. This is especially important for content blockers leveraging the CSP to block resources such as scripts and images.

Handling SameSite cookie restrictions

We’ve seen developers trying to work around SameSite cookie restrictions. If you have been using iframes on your extension pages and expecting them to behave like first party frames, the SameSite cookie attribute will keep your add-on from working properly. In Firefox 77, the cookies for these frames will behave as if it was a first party request. This should ensure that your extension continues to work as expected.

Other updates

Please also see these additional changes:

I’m very excited about the number of patches from the community that are included in this release. Please congratulate Tom Schuster, Ajitesh, Tobias, Mélanie Chauvel, Atique Ahmed Ziad, and a few teams across Mozilla that are bringing these great additions to you. I’m looking forward to finding out what is in store for Firefox 78, please stay tuned!