Extension Permissions are used to determine which capabilities are exposed to a given extension. They are specified in the extension’s manifest.json file.
This document describes the internal implementation of extension permissions. For more general extension permission information, see the public documentation on declaring permissions and permission warnings.
There are three basic classes of permissions.
API permissions are typically used to grant an extension access to a specific API. These are usually specified by a reserved string (like the API name). Examples include
storage, and others.
Match patterns provide access to a set of urls. Match patterns can encompass multiple hosts, so a single pattern may provide access to many different domains (or even, every domain). For more information, see the public match pattern documentation. In the codebase, match patterns are implemented as URLPattern.
Explicit host permissions are match patterns specified in the
permissions key of the extension’s manifest. These patterns control access to APIs that read or modify host data, such as
Note: Any path component is currently ignored for explicit hosts in permissions parsing.
Scriptable hosts are match patterns used in the content_scripts entry of the extension’s manifest. These only control which sites an extension can use content scripts on, and do not affect any other API.
From a messaging standpoint, we treat both explicit hosts and scriptable hosts the same (with each allowing the extension to read and modify data on one or more domains). The distinction is only to provide granular permissions in order to restrict what we provide the extension.
A manifest permission is a specified manifest entry that provides an extension with some permission. Examples of this include page overrides (to allow extensions to override a page, like the New Tab Page), externally_connectable (allowing extensions to communicate with websites or extensions), and bluetooth (allowing the extension to communicate with specific bluetooth devices). Manifest permissions are effectively similar to API permissions in that they provide access to a certain capability. From an implementation standpoint, permissions can often be implemented as either an API Permission or a Manifest Permission. For the rest of this document, we group both API and manifest permissions into “API permissions”.
Permissions are stored in the Preferences file, under the extension’s entry. We always store two different sets of permissions: granted permissions and active permissions (with the runtime host permissions feature, we will store a third, runtime granted permissions - this is described below). Note that neither of these include any non-persistent permissions.
Granted permissions are the permissions that the extension has ever been granted by the user (and have not been revoked by the user). When the user installs an extension, we grant the accepted permissions. If the extension is granted more permissions at any point, we update the set of granted permissions to include those. Extensions can be granted additional permissions through either an extension update that requires new permissions (assuming the user agrees) or through the permissions API (which is used for optional permissions). Granted permissions can be thought of as the maximum level of permissions an extension may have.
Active permissions are the permissions that an extension currently has. This set is used to initialize extension permission state when the extension is loaded, and determines the APIs and domains an extension can access.
The sets of active permissions and granted permissions can differ in a few scenarios.
chrome.permissions.request()), the user is prompted to accept or refuse it. If the user accepts, the permission is added to both the active and granted permissions. The extension can then remove this permission using
chrome.permissions.remove(). Removing the permission removes it from the active permissions (reducing the extension’s immediate capabilities), but does not remove it from the granted permissions. If the extension uses
chrome.permissions.request()for the same permission after removing it, the user will not be prompted again because the permission is present in the granted permissions.
Some permissions are granted ephemerally, and are not stored or persisted. These are tab-specific permissions in the code, and are used with the
activeTab permission. This provides the extension with temporary access to a tab, so that it can use
webRequest API, see the tab's URL and favicon with the
tabs API, and capture the screen with the
chrome.tabs.captureTab() function. When the user closes or navigates the tab, the permission is revoked.
When an extension is updated to a new version, the new version can include new permissions. Chrome will disable the extension if it is detected that the new version contains higher privilege than what is currently granted to the extension (see also Determining Privilege Increase). Note that this compares the new set of requested permissions to the granted permissions, rather than the active permissions for the extension. This distinction is important when the granted set is different than the active set. Consider the two following cases:
Most permissions have an associated warning string, which describes what the permission allows the extension to do. Permission warnings are shown to the user at a number of different times:
In order to maximize the benefit to users, Chrome tries to show as few warnings as possible, while ensuring they are still accurate.
Some permissions (like the
storage API) are considered relatively harmless, and will not generate a permission warning.
Certain permissions “contain” or imply other permissions. With host permissions, this is easy to understand: if an extension has access to all google.com sites (i.e.,
*://*.google.com/*), requesting access to a specific google.com site (
https://maps.google.com/*) is redundant. We should not warn the user that the extension wants to both “access all google.com sites” and “access maps.google.com”.
API permissions can be similarly redundant, if one API provides the same or more privilege than another. For instance, if an extension has access to a user’s history, then it implicitly has access to the user’s top sites. Thus, if an extension requests both the
history permission and the
topSites permission, we will only display a single warning to the user.
Not all permission changes result in disabling the extension. In order to calculate if an extension has escalated privilege and should be disabled, Chrome compares the permission messages that are associated with the granted permissions and the newly-requested permissions. This is different than comparing the permissions themselves because of messageless permissions and permission collapsing.
This has implications when determining privilege increase. If an extension adds new permissions but all of those permissions are either a) messageless or b) collapsed into already-granted permissions, then the extension is not disabled. Otherwise, Chrome considers it a privilege increase, disables the extension, and notifies the user (allowing them to accept the new permissions and re-enable it, if they want).
Note: since optional permissions are not granted automatically, adding optional permissions in a new version will never disable the extension.
Granted permissions are not currently synced. Instead, we sync the disable reasons for an extension (which can include that an extension was disabled for a permissions increase) and the extension version. In most cases, this allows users to approve an extension only once and have it enabled on all devices. When the extension is updated to a new version, if it has increased permissions, it will be disabled on the device. The user can then approve the new permissions, which enables the extension. When the user goes to a new device, the extension will be updated, and Chrome will notice the increased permissions, but since the extension has been approved in sync, it will not be disabled.
There are two known issues related to syncing extensions:
Runtime host permissions is a new feature that allows users to have more control over when and where their extensions run. This allows the user to install an extension that requests permission to multiple hosts, but have a choice over if it runs.
The runtime host permissions feature introduces a number of permissions-related concepts.
Withheld permissions are stored on the Extension object (as part of the PermissionsData class). Withheld permissions are the set of permissions that were listed as required permissions by the extension, but were withheld as part of the runtime host permissions feature. The extension does not have acccess to these permissions.
Runtime-granted permissions are stored within extension preferences, and represent the permissions that the user has granted the extension at runtime. This is deliberately kept as a separate set from granted permissions in order to ensure that experimentation with the feature is independent, and will not affect extensions when the feature is disabled.
Runtime-granted permissions include permissions granted through dedicated UI for the runtime host permissions feature (such as context menu controls and controls in the chrome://extensions page) as well as optional permissions granted through the
The controls for granting runtime permissions allow granting permissions beyond what the extension specifically requests. This is so that the user can grant
https://google.com/*, even if the extension only requested
https://google.com/maps. This is useful for two reasons. First, it presents a simpler UI to the user (who doesn't need to worry about granting exactly the correct URL pattern); secondly, it means if the extension later requests an additional pattern within the same host, it will be automatically granted.
However, though the runtime-granted permissions may extend beyond what is explicitly requested, the current permissions on the extension object itself (or granted to the extension process) should not. This provides us increased security, since we don't want to have extensions privileged beyond what they should need.
With the runtime host permissions feature, calculating current permissions is a little more complex. Typically, an extension's current permissions are calculated as
current_permissions = intersection(active_permissions, union(required_permissions, optional_permissions))
Said differently, an extension‘s permissions are equal to any permissions in the active permission set that also appear in either the required or optional sets. This ensures that the extension never has access to permissions that it didn’t request, which is important for security reasons (we don't want an over-privileged process if we can avoid it).
With runtime host permissions, this calculation is a little more difficult:
current_permissions_without_feature = intersection(active_permissions, union(required_permissions, optional_permissions)) current_permissions = intersection(current_permissions_without_feature, runtime_granted_permissions)
The system will withhold permissions that were not within the set of runtime-granted permissions. As noted above, the runtime-granted permissions may include more than what was explicitly requested by the extension; however, we will not extend these permissions to the extension object because these additional permissions will not be present on in the required or optional permissions.
With runtime host permissions, it's possible that the user will grant a host permission that overlaps with a requested host, but is neither a direct match nor a strict subset. For instance, an extension may request the pattern
*://google.com/maps, and a user may grant
https://*.google.com/*. In this case, we should neither grant
*://google.com/maps (which includes origins the user did not approve, nor grant
https://*.google.com/* (which includes more than the extension requires). Instead, we should grant the extension
https://google.com/maps - the intersection of the granted permission and the requested permission.
We perform this calculation with runtime host permissions. This has the implication that permissions granted to the extension object may not be explicitly present within the extension's required or optional permissions, but rather contained by one of those sets.