Examples¶
Practical patterns for classifying a Chrome extension's permissions with
ext-permission-risk. These mirror the audit flow used by the
zovo.one extension scanner.
Classify a single permission¶
The simplest case: look up one token from a manifest.
use ext_permission_risk::{risk_of, RiskLevel};
let info = risk_of("cookies").unwrap();
println!("cookies: {} — {}", info.level.label(), info.description);
// cookies: HIGH — Reads and modifies all cookies for any site the extension
// has host access to, including session and auth cookies.
Classify a whole manifest¶
A manifest has two arrays — permissions (named API tokens) and
host_permissions (match-patterns). Classify both with
risk_of_or_pattern, which recognises host patterns in addition to named
tokens.
use ext_permission_risk::{risk_of_or_pattern, highest_risk, RiskLevel};
let manifest_perms = [
"activeTab", "storage", "cookies", // named tokens
"https://*.example.com/*", // scoped host pattern
];
// Overall risk: the max across every token.
let overall = highest_risk(manifest_perms.iter().copied());
assert_eq!(overall, Some(RiskLevel::High)); // cookies dominates
// Per-permission breakdown.
for p in manifest_perms {
let r = risk_of_or_pattern(p);
println!("{:<28} {} {}", p, r.level.label(), r.description);
}
Recognise host match-patterns¶
<all_urls> and *://*/* grant access to the entire web and are High.
A scoped pattern like https://*.example.com/* grants access to one domain
family and is Medium — meaningfully less broad.
use ext_permission_risk::{risk_of_or_pattern, RiskLevel};
assert_eq!(risk_of_or_pattern("<all_urls>").level, RiskLevel::High);
assert_eq!(risk_of_or_pattern("https://*/*").level, RiskLevel::High);
assert_eq!(risk_of_or_pattern("https://*.example.com/*").level, RiskLevel::Medium);
Compute a verdict¶
A common scanner pattern: derive a one-word verdict from the highest risk present.
use ext_permission_risk::{highest_risk, RiskLevel};
fn verdict(perms: &[&str]) -> &'static str {
match highest_risk(perms.iter().copied()) {
Some(RiskLevel::High) => "dangerous — requests broad access, review carefully",
Some(RiskLevel::Medium) => "caution — sensitive access, check the publisher",
Some(RiskLevel::Low) => "low risk — minimal access requested",
None => "no recognised permissions",
}
}
assert_eq!(verdict(&["activeTab", "storage"]), "low risk — minimal access requested");
assert_eq!(verdict(&["tabs", "history"]), "caution — sensitive access, check the publisher");
assert_eq!(verdict(&["cookies", "<all_urls>"]), "dangerous — requests broad access, review carefully");
Iterate the full table¶
Render a complete reference page, or audit every permission the table knows about.
use ext_permission_risk::{all_permissions, RiskLevel};
let high: Vec<_> = all_permissions()
.iter()
.filter(|p| p.level == RiskLevel::High)
.map(|p| p.permission)
.collect();
println!("{} HIGH-risk permissions known", high.len());
assert!(high.contains(&"cookies"));
assert!(high.contains(&"<all_urls>"));
Integration note¶
This crate deliberately has no JSON or manifest-parsing dependency —
the scanner is expected to parse manifest.json itself (with serde_json
or similar) and pass the resulting permissions / host_permissions
string arrays to risk_of / risk_of_or_pattern. That keeps the
classification logic pure, testable, and reusable across any Rust tool that
wants to reason about extension permissions — including the
zovo.one scanner.