Auditing Chrome extension permissions in 2026: a 3-minute check
Yes, you can audit a Chrome extension in about three minutes: open chrome://extensions, turn on Developer mode, copy the extension ID, and read the
permissionsandhost_permissionsarrays in its manifest.json. Score what you find, and treat pairs likecookiesplus<all_urls>as red flags. A scanner automates the judgment, but the manifest is the ground truth.
Full disclosure: the Extension Guard tool I link to further down is one I built. I tried four permission checkers in 2025 and every single one wanted me to upload the extension's CRX file to their server, which felt backwards for a security tool. Extension Guard is free, runs client-side in your browser, needs no signup, and never uploads anything. If you've found a better one, honestly, tell me in the comments.
The extension that made me paranoid
In December 2024, attackers phished the developer of the Cyberhaven extension and shipped a malicious update straight through the Chrome Web Store. The same campaign compromised around 36 extensions with roughly 2.6 million combined users. Nobody clicked a shady download link. The extensions people already trusted changed underneath them, silently, on autoupdate.
It wasn't the first time either. In January 2021, The Great Suspender, a tab manager with over two million users, got yanked from the Web Store after its new owner shipped tracking code in an update. The original developer had quietly sold the extension in mid-2020, and most users had no idea anything changed hands until Chrome flagged it as malware. The pattern repeated with Cyberhaven: an update landed on permissions people had granted years earlier, and those permissions did all the work.
Then it got personal. Three weeks ago I was debugging why a client's checkout page behaved differently in my normal browser than in Incognito, and after 47 minutes of blaming my own code I found the real cause: a coupon extension I'd installed sometime in 2023 was injecting a content script into every page I visited. It had permission to do that from day one. I'd granted it myself. I'd just never read the manifest.
Chrome's install prompt deserves some blame. It tells you an extension can "read and change all your data on all websites", and it says exactly the same thing for a password manager, an ad blocker, and a keylogger. When one sentence covers everything, people stop reading it. The useful signal lives one layer down, in manifest.json: which permissions the developer asked for, and which ones appear together.
That last part matters more than any single permission. storage is harmless. cookies alone usually means session handling. Pair cookies with <all_urls>, though, and the extension can read your logged-in session on every site you visit, which is exactly what the Cyberhaven payload went after.
How the scoring works under the hood
The core idea fits in a script. Every permission gets a weight, and host patterns get scored by breadth (*://*.example.com/* is a different animal from <all_urls>). Dangerous pairs then add points on top of the sum. Here's a stripped-down version of the logic you can run against any manifest right now:
// score-extension.js
// usage: node score-extension.js path/to/manifest.json
const fs = require("fs");
const WEIGHTS = {
"<all_urls>": 30, "debugger": 40, "nativeMessaging": 35,
"webRequest": 20, "cookies": 25, "scripting": 20,
"tabs": 15, "history": 20, "clipboardRead": 25,
"management": 20, "downloads": 10, "storage": 2,
};
// pairs that are worse together than apart
const COMBOS = [
["cookies", "<all_urls>", "can read session cookies on every site"],
["webRequest", "<all_urls>", "can watch every request you make"],
["scripting", "<all_urls>", "can inject code into any page"],
["tabs", "history", "can build a full browsing profile"],
];
const manifest = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
const perms = [
...(manifest.permissions || []),
...(manifest.host_permissions || []),
];
let score = perms.reduce((sum, p) => sum + (WEIGHTS[p] || 5), 0);
for (const [a, b, why] of COMBOS) {
if (perms.includes(a) && perms.includes(b)) {
score += 25;
console.log(`combo: ${a} + ${b} -> ${why}`);
}
}
const band = score > 60 ? "high" : score > 30 ? "medium" : "low";
console.log(`risk score: ${score} (${band})`);
Run it with node score-extension.js manifest.json. The coupon extension that burned me asked for scripting, cookies, storage, and host access to <all_urls>. This script flags two combos on it and scores it 127, which would've been useful to see in 2023 before I clicked install.
Why score pairs instead of just summing weights? Because permissions compose. Post-MV3, webRequest on its own mostly lets an extension observe traffic. <all_urls> on its own is reach with nothing attached to it. Together they mean every request you make, from your bank session to your company's admin panel, is visible to the extension. A plain sum understates that badly. I tuned the weights against a few hundred real manifests, and the combo bonus was the single change that made the scores match my gut.
Extension Guard is this script grown up: a weight table covering all 60-plus Chrome permissions, combo detection with plain-English explanations of what each pairing enables, and a paste-in box so you don't need Node installed. You paste the manifest and it scores locally in your browser. The weights started as a JSON file I kept for vetting my own installs, and the tool is mostly a UI wrapped around that file.
Getting the manifest is the only fiddly step. On macOS, installed extensions live under ~/Library/Application Support/Google/Chrome/Default/Extensions/<id>/<version>/manifest.json. On Windows, look in %LOCALAPPDATA%\Google\Chrome\User Data\Default\Extensions. For something you haven't installed yet, the CRX Viewer extension (ironic, I know) shows you the manifest straight from a Web Store listing.
How it stacks up against the alternatives
I used three other approaches before building my own, and I still use two of them. Here's the honest comparison:
| What | Extension Guard | ExtensionTotal | CRX Viewer | Manual review |
|---|---|---|---|---|
| Where it runs | Client-side, in your browser | Their servers | Client-side | Your editor |
| Signup | No | For full reports | No | No |
| Combo detection | Yes, with explanations | Partial | No scoring at all | Only if you know the pairs |
| Sees actual code | No | Yes | Yes | Yes |
| Cost | Free | Free tier, paid API | Free | Your time |
ExtensionTotal is genuinely good, and I still reach for it when I want signals beyond the manifest, like developer reputation and code analysis. The trade-off is that you're querying their backend, and the deeper reports sit behind an account. CRX Viewer is the opposite: full source access with zero interpretation. It shows you everything and explains nothing, which is fine if you already know what chrome.debugger buried in a minified bundle means.
CRXcavator used to be the obvious answer here. Duo Security built it, and it was excellent right up until they retired it. That shutdown is a big part of why the surviving options went cloud-side, and why I built mine to run locally instead. Cloud scanners can do more (they fetch the code, they track version history), but a manifest score shouldn't require sending anything anywhere.
When you shouldn't use it
A permission scanner reads declared capability. It can't see intent and it can't see runtime behavior, and that puts some hard limits on when Extension Guard is the right call.
A malicious update can keep the same permission set. The Cyberhaven attackers didn't request anything new; the extension already had the access they needed. Extension Guard would've scored the compromised version identically to the clean one. A scan tells you the blast radius if an extension ever goes bad. Whether it actually has gone bad is a different investigation, one that involves reading code and watching network traffic.
Open source extensions deserve an actual code read. If the repo is public and reasonably small, an hour with the source beats any score. The manifest tells you what the extension may do. The code tells you what it does.
Enterprise fleets need policy, and a scanner is the wrong layer. If you manage 200 machines, use Chrome's ExtensionInstallAllowlist and force-install policies. Scan candidates before they go on the allowlist, sure, but enforcement has to live in policy or people will quietly work around you.
Low scores can still hurt you. An extension with nothing beyond activeTab can still draw a convincing fake login popup. I don't have a good automated answer for that class of attack, and I'm suspicious of anyone who claims they do.
FAQ
Q: Does a high risk score mean an extension is malicious?
A: No. My password manager scores 88. A high score measures capability: how much damage the extension could do if it went rogue or got compromised. Score is blast radius. Whether you trust the developer is a separate judgment, and no scanner can make it for you.
Q: Where do I find the manifest for an installed extension?
A: Open chrome://extensions with Developer mode on and copy the extension's ID. Then find that ID inside your Chrome profile's Extensions folder (exact paths are in the section above) and open the manifest.json in the newest version folder. CRX Viewer works if you'd rather check without installing anything first.
Q: Didn't Manifest V3 fix all this?
A: I assumed it would, and I was mostly wrong. MV3 removed blocking webRequest for regular extensions and banned remotely hosted code, which are real improvements. But pairing cookies and scripting with <all_urls> is still perfectly legal in MV3, and the Cyberhaven attack happened well into the MV3 era.
Q: Does the scoring work for Firefox or Edge add-ons?
A: Mostly. Edge uses the same manifest format, so everything applies there. Firefox overlaps on most permission names; the scoring still runs, but a few Firefox-specific permissions fall back to a default weight, so treat those scores as a rough draft.
Q: Can I use this in CI for extensions my team ships?
A: Yes. Add process.exit(score > 60 ? 1 : 0) to the script above and wire it into your build. We run a version of that check before every store submission, and it caught an accidental <all_urls> grant in a pull request back in April 2026.
Written with AI assistance and human review. Try the tool at aidevhub.io/extension-guard.
Top comments (0)