Unused Permission Expiry
Persistent site permissions (camera, microphone, geolocation, etc.) do not traditionally expire. This can be a privacy and security concern: users may forget they granted a site access to powerful capabilities, especially after not visiting the site for a long time.
To address this, the permission manager can automatically expire permissions for sites the user has not interacted with recently. Rather than a simple lifetime cap on all permissions, this approach targets only inactive sites, so frequently-used sites keep their permissions.
Note
This feature is currently enabled on Nightly builds only.
How It Works
Interaction tracking. Each time the user activates (clicks, types, etc.) a page, the content process sends an IPC message (
RecordUserInteractionForPermissions) to the parent process. The permission manager records the current timestamp for the page’s origin in themoz_origin_interactionsdatabase table.Expiry check. On the
idle-dailyobserver notification, the permission manager runsExpireUnusedPermissions(). For each persistent permission whose type is in the configurable allowlist, it checks whether the origin’s last interaction timestamp is older than the expiry threshold. If so, the permission is removed. If there is no interaction data for an origin, its permissions are not expired.Cleanup. Orphaned interaction records (origins with no remaining permissions) are cleaned up on
idle-dailyand when permissions are removed throughClearDataService.
Important
Interaction tracking is always active, even when the expiry feature itself is disabled. This allows the interaction store to warm up before the feature is enabled, so that expiry decisions are based on real usage data from day one.
However, for profiles where the interaction store has only recently started collecting data, the permission manager must first observe user interactions with sites before it can expire their permissions. Since permissions without interaction data are never expired, users will have to wait at least the full expiry threshold (default: 13 months) after interactions are first recorded before any permissions are actually removed.
Configuration
Three preferences control the feature (see their definitions in modules/libpref/init/StaticPrefList.yaml):
permissions.expireUnused.enabled
Enables or disables the expiry mechanism. Currently enabled on Nightly only.
permissions.expireUnusedThresholdSec
Duration in seconds of site inactivity after which permissions are eligible for expiry.
permissions.expireUnusedTypes
Comma-separated list of permission types that can be expired due to inactivity.
Double-keyed permission types include the ^ delimiter (e.g.,
open-protocol-handler^). This list is derived from the site permissions
defined in browser/modules/SitePermissions.sys.mjs.
Interaction Tracking
User interactions are tracked in the moz_origin_interactions table in the
permissions database (added in schema version 13).
The flow for recording an interaction:
Document::MaybeStoreUserInteractionAsPermission()(in dom/base/Document.cpp) fires on first user activation in a document.In the content process,
PermissionManager::RecordSiteInteraction()(in extensions/permissions/PermissionManager.cpp) sendsPWindowGlobal::RecordUserInteractionForPermissions()via IPC.In the parent process,
WindowGlobalParentreceives the message and callsPermissionManager::UpdateLastInteractionForPrincipal(), which dispatches a write to the permissions database thread.
Interactions in private browsing are not recorded.
Origin Attributes Handling
Interaction timestamps are stored with origin attributes (OA) stripped, so a single timestamp represents all OA variants of the same origin.
During the expiry check, certain permission types that are forced to strip OA
(e.g., cookie, https-only-load-insecure) are looked up against a
separate OA-stripped index. This ensures the expiry logic correctly matches
interactions to permissions regardless of origin attribute context.
Data Cleanup
Orphaned interaction records (entries in moz_origin_interactions whose origin
has no corresponding entry in moz_perms) are removed:
Automatically during
idle-dailymaintenance.After per-entry permission removal in
ClearDataService, via theremoveOrphanedInteractionRecords()IDL method.Bulk removal methods (e.g.,
removeAll,removePermissionsWithAttributes) handle cleanup internally.
IDL API
Two methods were added to nsIPermissionManager:
updateLastInteractionForPrincipal
Manually update the last interaction timestamp for a principal. Skips system principals and private browsing contexts.
removeOrphanedInteractionRecords
Returns a Promise that resolves once orphaned interaction records have been
deleted. Used by ClearDataService to ensure interaction data is cleaned up
alongside permissions.
Telemetry
Three Glean metrics are recorded each time permissions are expired (see extensions/permissions/metrics.yaml for full definitions):
permissions.unused_permission_age_at_expiry – distribution of time since last site interaction when a permission was expired.
permissions.unused_permissions_expired_by_type – count of expired permissions broken down by permission type.
permissions.unused_permission_modified_age_at_expiry – distribution of time since the permission was last modified when it was expired.