#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum RiskLevel {
Low,
Medium,
High,
Critical,
}
impl RiskLevel {
pub fn label(self) -> &'static str {
match self {
RiskLevel::Low => "LOW",
RiskLevel::Medium => "MEDIUM",
RiskLevel::High => "HIGH",
RiskLevel::Critical => "CRITICAL",
}
}
pub fn summary(self) -> &'static str {
match self {
RiskLevel::Low => "Low risk: scoped or sandboxed access with no broad reach.",
RiskLevel::Medium => {
"Medium risk: meaningful access to a category of user data or a named site."
}
RiskLevel::High => {
"High risk: broad, persistent cross-origin or sensitive-system access."
}
RiskLevel::Critical => {
"Critical risk: effectively total control of pages, sessions, or the machine."
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PermissionEntry {
pub token: &'static str,
pub level: RiskLevel,
pub description: &'static str,
}
#[rustfmt::skip]
pub const RISK_DATABASE: &[PermissionEntry] = &[
PermissionEntry {
token: "activeTab",
level: RiskLevel::Low,
description: "Grants temporary access to the current tab only when the user \
explicitly clicks the extension action. No persistent background \
access to any site.",
},
PermissionEntry {
token: "contextMenus",
level: RiskLevel::Low,
description: "Adds items to the browser's right-click context menu. No page \
content access by itself.",
},
PermissionEntry {
token: "storage",
level: RiskLevel::Low,
description: "Stores extension data locally (synced/local). Confined to the \
extension's own sandbox; cannot read site data.",
},
PermissionEntry {
token: "alarms",
level: RiskLevel::Low,
description: "Schedules code to run at a future time. No content access by \
itself.",
},
PermissionEntry {
token: "idle",
level: RiskLevel::Low,
description: "Detects when the machine is idle or locked. No page content \
access.",
},
PermissionEntry {
token: "notifications",
level: RiskLevel::Low,
description: "Shows desktop notifications. No page content access.",
},
PermissionEntry {
token: "offscreen",
level: RiskLevel::Low,
description: "Creates offscreen documents for DOM work without a visible page. \
No extra site access by itself.",
},
PermissionEntry {
token: "power",
level: RiskLevel::Low,
description: "Keeps the screen or system awake. No content access.",
},
PermissionEntry {
token: "sidePanel",
level: RiskLevel::Low,
description: "Shows content in the browser side panel. No extra host access by \
itself.",
},
PermissionEntry {
token: "tts",
level: RiskLevel::Low,
description: "Text-to-speech output. No content access.",
},
PermissionEntry {
token: "unlimitedStorage",
level: RiskLevel::Low,
description: "Removes the extension storage quota. No extra site access.",
},
PermissionEntry {
token: "userScripts",
level: RiskLevel::Low,
description: "Registers user-authored scripts (the MV3 user-script API). \
Powerful if a user installs a hostile script, but grants no \
host access the user did not already consent to.",
},
PermissionEntry {
token: "declarativeNetRequest",
level: RiskLevel::Low,
description: "Blocks or modifies network requests via static rules (the MV3 \
content-blocker path). Less powerful than webRequest blocking, \
but can still read request URLs.",
},
PermissionEntry {
token: "declarativeNetRequestFeedback",
level: RiskLevel::Low,
description: "Observes which declarativeNetRequest rules matched. No extra \
host access.",
},
PermissionEntry {
token: "gcm",
level: RiskLevel::Low,
description: "Receives push messages via Google Cloud Messaging. No content \
access.",
},
PermissionEntry {
token: "action",
level: RiskLevel::Low,
description: "Configures the extension's toolbar action icon. No host access.",
},
PermissionEntry {
token: "favicon",
level: RiskLevel::Low,
description: "Reads favicons for URLs. No page content access.",
},
PermissionEntry {
token: "declarativeContent",
level: RiskLevel::Low,
description: "Reacts to page URL/CSS state via declarative rules. No arbitrary \
script execution.",
},
PermissionEntry {
token: "bookmarks",
level: RiskLevel::Medium,
description: "Reads and modifies the user's full bookmark tree.",
},
PermissionEntry {
token: "history",
level: RiskLevel::Medium,
description: "Reads and clears the user's full browsing history.",
},
PermissionEntry {
token: "downloads",
level: RiskLevel::Medium,
description: "Initiates, monitors, and opens downloads; can open arbitrary \
files from the download shelf.",
},
PermissionEntry {
token: "downloads.open",
level: RiskLevel::Medium,
description: "Opens downloaded files on disk. Combined with a hostile download \
this can execute local content.",
},
PermissionEntry {
token: "downloads.shelf",
level: RiskLevel::Medium,
description: "Hides or shows the download shelf; can mask a stealthy \
download.",
},
PermissionEntry {
token: "downloads.ui",
level: RiskLevel::Medium,
description: "Controls the downloads UI surface.",
},
PermissionEntry {
token: "geolocation",
level: RiskLevel::Medium,
description: "Reads the user's GPS / IP-derived location (subject to a per-site \
permission prompt).",
},
PermissionEntry {
token: "clipboardWrite",
level: RiskLevel::Medium,
description: "Writes to the system clipboard. Can overwrite a copied password \
or inject pasted content.",
},
PermissionEntry {
token: "clipboardRead",
level: RiskLevel::Medium,
description: "Reads the system clipboard, which frequently contains copied \
passwords, tokens, or private text.",
},
PermissionEntry {
token: "identity",
level: RiskLevel::Medium,
description: "Triggers OAuth sign-in and obtains the user's signed-in account \
email / profile and an auth token.",
},
PermissionEntry {
token: "identity.email",
level: RiskLevel::Medium,
description: "Returns the user's signed-in email address directly.",
},
PermissionEntry {
token: "management",
level: RiskLevel::Medium,
description: "Lists, enables, disables, and uninstalls other installed \
extensions.",
},
PermissionEntry {
token: "tabs",
level: RiskLevel::Medium,
description: "Reads the URL and title of every open tab and receives tab-update \
events. Effectively full browsing-session visibility.",
},
PermissionEntry {
token: "tabGroups",
level: RiskLevel::Medium,
description: "Reads and modifies tab groups, exposing which sites the user \
clusters together.",
},
PermissionEntry {
token: "topSites",
level: RiskLevel::Medium,
description: "Reads the user's most-visited sites (the new-tab shortcuts).",
},
PermissionEntry {
token: "sessions",
level: RiskLevel::Medium,
description: "Reads recently closed tabs and windows across devices.",
},
PermissionEntry {
token: "pageCapture",
level: RiskLevel::Medium,
description: "Saves the current page as an MHTML archive, capturing rendered \
content.",
},
PermissionEntry {
token: "search",
level: RiskLevel::Medium,
description: "Sets the default search provider and issues queries.",
},
PermissionEntry {
token: "browsingData",
level: RiskLevel::Medium,
description: "Clears cookies, cache, history, and other browsing data — can \
wipe a user's session.",
},
PermissionEntry {
token: "fontSettings",
level: RiskLevel::Medium,
description: "Changes browser font settings.",
},
PermissionEntry {
token: "readingList",
level: RiskLevel::Medium,
description: "Reads and modifies the user's reading list.",
},
PermissionEntry {
token: "cookies",
level: RiskLevel::High,
description: "Reads and modifies all cookies for any site the extension has \
host access to, including session and auth cookies.",
},
PermissionEntry {
token: "webRequest",
level: RiskLevel::High,
description: "Observes (and in MV2 could block) every network request and \
response, exposing full URLs, headers, and bodies including \
credentials.",
},
PermissionEntry {
token: "webRequestBlocking",
level: RiskLevel::High,
description: "MV2-only blocking webRequest — full request interception and \
modification. Removed from MV3.",
},
PermissionEntry {
token: "debugger",
level: RiskLevel::High,
description: "Attaches the Chrome DevTools Protocol to a tab, giving full DOM, \
network, and JS execution control — effectively total control \
of the page.",
},
PermissionEntry {
token: "nativeMessaging",
level: RiskLevel::High,
description: "Talks to a native application installed on the user's machine. \
Escapes the browser sandbox entirely.",
},
PermissionEntry {
token: "fileSystem",
level: RiskLevel::High,
description: "Reads and writes files outside the browser sandbox (where granted \
by the platform).",
},
PermissionEntry {
token: "fileBrowserHandler",
level: RiskLevel::High,
description: "Reads and writes files via the ChromeOS file browser.",
},
PermissionEntry {
token: "proxy",
level: RiskLevel::High,
description: "Configures the browser's proxy settings. A hostile extension can \
redirect all traffic through an attacker-controlled server.",
},
PermissionEntry {
token: "privacy",
level: RiskLevel::High,
description: "Reads and changes privacy-related browser settings (do-not-track, \
third-party cookies, hyperlink auditing).",
},
PermissionEntry {
token: "system.cpu",
level: RiskLevel::High,
description: "Reads detailed CPU metadata useful for device fingerprinting.",
},
PermissionEntry {
token: "system.memory",
level: RiskLevel::High,
description: "Reads physical memory capacity, a device-fingerprinting signal.",
},
PermissionEntry {
token: "system.storage",
level: RiskLevel::High,
description: "Reads attached storage device metadata and can eject devices.",
},
PermissionEntry {
token: "system.network",
level: RiskLevel::High,
description: "Reads network interface metadata exposing the local network \
topology.",
},
PermissionEntry {
token: "system.display",
level: RiskLevel::High,
description: "Reads display metadata (resolution, DPI) usable for \
fingerprinting.",
},
PermissionEntry {
token: "system.audio",
level: RiskLevel::High,
description: "Reads audio device metadata.",
},
PermissionEntry {
token: "vpnProvider",
level: RiskLevel::High,
description: "Configures a VPN (ChromeOS), which can redirect and intercept \
all network traffic.",
},
PermissionEntry {
token: "enterprise.networkingAttributes",
level: RiskLevel::High,
description: "Reads detailed network attributes (ChromeOS enterprise), exposing \
internal network identity.",
},
PermissionEntry {
token: "enterprise.deviceAttributes",
level: RiskLevel::High,
description: "Reads ChromeOS enterprise device identity attributes.",
},
PermissionEntry {
token: "webNavigation",
level: RiskLevel::High,
description: "Receives the full navigation events of every frame in every tab, \
including the URL of every frame and redirect.",
},
PermissionEntry {
token: "scripting",
level: RiskLevel::High,
description: "Injects arbitrary JavaScript into pages for which the extension \
has host permission — full page control at runtime (MV3 \
successor to tabs.executeScript).",
},
PermissionEntry {
token: "contentSettings",
level: RiskLevel::High,
description: "Reads and modifies per-site content settings (cookies, \
javascript, plugins, mic, camera) for every origin.",
},
PermissionEntry {
token: "usbDevices",
level: RiskLevel::High,
description: "Accesses listed USB devices directly, bypassing the page.",
},
PermissionEntry {
token: "serial",
level: RiskLevel::High,
description: "Reads and writes to serial ports.",
},
PermissionEntry {
token: "bluetoothLowEnergy",
level: RiskLevel::High,
description: "Discovers and talks to BLE devices.",
},
PermissionEntry {
token: "hid",
level: RiskLevel::High,
description: "Talks to raw HID devices (keyboards, security keys).",
},
PermissionEntry {
token: "audio",
level: RiskLevel::High,
description: "Captures and renders audio from / to the system.",
},
PermissionEntry {
token: "audioModem",
level: RiskLevel::High,
description: "Encodes/decodes data over audio (ultrasonic pairing).",
},
PermissionEntry {
token: "bluetooth",
level: RiskLevel::High,
description: "Discovers and connects to Bluetooth devices.",
},
PermissionEntry {
token: "mdns",
level: RiskLevel::High,
description: "Discovers services on the local network via mDNS.",
},
PermissionEntry {
token: "platformInfo",
level: RiskLevel::High,
description: "Reads OS / arch / platform metadata for fingerprinting.",
},
PermissionEntry {
token: "processes",
level: RiskLevel::High,
description: "Observes browser process metadata and CPU usage per tab.",
},
PermissionEntry {
token: "networking.onc",
level: RiskLevel::High,
description: "Configures ChromeOS network connections (Open Network \
Configuration).",
},
PermissionEntry {
token: "networking.config",
level: RiskLevel::High,
description: "Configures network credentials on ChromeOS.",
},
PermissionEntry {
token: "documentScan",
level: RiskLevel::High,
description: "Reads from attached document scanners.",
},
PermissionEntry {
token: "accessibilityFeatures.modify",
level: RiskLevel::High,
description: "Modifies accessibility settings (can be abused to alter input \
handling).",
},
PermissionEntry {
token: "input",
level: RiskLevel::High,
description: "ChromeOS IME input — can observe keystrokes.",
},
PermissionEntry {
token: "languageSettings",
level: RiskLevel::High,
description: "Reads and changes the user's language settings.",
},
PermissionEntry {
token: "wallpaper",
level: RiskLevel::High,
description: "Sets the ChromeOS wallpaper.",
},
PermissionEntry {
token: "enterprise.hardwarePlatform",
level: RiskLevel::High,
description: "Reads hardware platform identity (enterprise).",
},
PermissionEntry {
token: "clipboard",
level: RiskLevel::High,
description: "Reads and writes the system clipboard (combined read+write).",
},
PermissionEntry {
token: "<all_urls>",
level: RiskLevel::Critical,
description: "Requests host access to every site on the web. Combined with \
content scripts or scripting this means any page's content, \
forms, and credentials can be read and modified at will — the \
canonical spyware grant.",
},
PermissionEntry {
token: "*://*/*",
level: RiskLevel::Critical,
description: "Match pattern granting host access to every http/https URL. \
Equivalent in effect to <all_urls> for normal browsing.",
},
PermissionEntry {
token: "http://*/*",
level: RiskLevel::Critical,
description: "Host access to every plain-http URL, including login pages and \
intranet sites.",
},
PermissionEntry {
token: "https://*/*",
level: RiskLevel::Critical,
description: "Host access to every secure URL on the web.",
},
PermissionEntry {
token: "*://*",
level: RiskLevel::Critical,
description: "Truncated but still blanket http/https host access.",
},
PermissionEntry {
token: "file:///*",
level: RiskLevel::Critical,
description: "Host access to local files via the file:// scheme, subject to \
the 'allow access to file URLs' toggle. Reads files on disk.",
},
PermissionEntry {
token: "urn:*",
level: RiskLevel::Critical,
description: "Host access to URN resources (broad scheme grant).",
},
];
pub fn find_permission(token: &str) -> Option<&'static PermissionEntry> {
RISK_DATABASE.iter().find(|e| e.token == token)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn database_is_comprehensive() {
assert!(RISK_DATABASE.len() >= 60, "only {} entries", RISK_DATABASE.len());
let crit = RISK_DATABASE.iter().filter(|e| e.level == RiskLevel::Critical).count();
let high = RISK_DATABASE.iter().filter(|e| e.level == RiskLevel::High).count();
let med = RISK_DATABASE.iter().filter(|e| e.level == RiskLevel::Medium).count();
let low = RISK_DATABASE.iter().filter(|e| e.level == RiskLevel::Low).count();
assert!(crit >= 5, "need >=5 Critical entries, got {crit}");
assert!(high >= 25, "need >=25 High entries, got {high}");
assert!(med >= 12, "need >=12 Medium entries, got {med}");
assert!(low >= 12, "need >=12 Low entries, got {low}");
}
#[test]
fn every_entry_round_trips_through_lookup() {
for entry in RISK_DATABASE {
let found = find_permission(entry.token);
assert!(found.is_some(), "{:?} not found", entry.token);
assert_eq!(found.unwrap().level, entry.level);
assert!(entry.description.len() >= 25, "thin description for {:?}", entry.token);
}
}
#[test]
fn canonical_high_risk_tokens_present() {
for tok in ["cookies", "webRequest", "debugger", "nativeMessaging", "scripting", "webNavigation"] {
assert!(find_permission(tok).is_some(), "missing {tok}");
}
}
#[test]
fn canonical_critical_tokens_present() {
for tok in ["<all_urls>", "*://*/*", "https://*/*", "file:///*"] {
assert!(find_permission(tok).is_some(), "missing {tok}");
}
}
#[test]
fn unknown_token_is_none_not_critical() {
assert!(find_permission("totally-fake-xyz").is_none());
assert!(find_permission("").is_none());
}
#[test]
fn risk_level_ordering() {
assert!(RiskLevel::Low < RiskLevel::Medium);
assert!(RiskLevel::Medium < RiskLevel::High);
assert!(RiskLevel::High < RiskLevel::Critical);
}
#[test]
fn labels_and_summaries() {
for lvl in [RiskLevel::Low, RiskLevel::Medium, RiskLevel::High, RiskLevel::Critical] {
assert!(!lvl.label().is_empty());
assert!(lvl.summary().len() > 20);
}
}
}