Extension viewer: check a browser extension before you install it
Got a .crx or .xpi from a developer's site, a forum or a colleague, or worried about one you already run after news of a hijacked extension? See what it asks for and what its code reaches for: every permission in one plain sentence, the sites it can read and change, where its updates come from, and the lines where it runs strings as code or loads scripts from other servers.
The file is read by this tab only. It is not uploaded, not installed and not run.
What it shows
- Which extension it is. The name (looked up in
_localeswhen the manifest says__MSG_appName__), version, Manifest V2 or V3, author and homepage, and the extension ID: for a .crx it is worked out from the public key in the file's header, so you can compare it with the ID in a Chrome Web Store address or onchrome://extensions. A Firefox add-on shows itsgecko.id. - Every permission, in one sentence of our own, with a risk band.
cookiesmeans it can read your login cookies on the sites it reaches;webRequestmeans it watches the requests your browser makes;historymeans your whole browsing history;storageandalarmsare housekeeping. Optional permissions, which it asks for later, are marked. - The sites it can read and change. Host permissions and content-script patterns are turned into plain sites:
<all_urls>is every site you visit,https://*.example.com/*is example.com and all its subdomains over https. Also who may message it (externally_connectable), its content security policy, and the files any page may load from it. - Where its updates come from.
update_urlis flagged when it is not the Chrome Web Store or addons.mozilla.org: then a server of the developer's own decides what the next version contains, and no store looks at it. - What its code reaches for. Every script and page is searched as text for
eval(,new Function(, timers given a string, script addresses outside the package, and every outside host named in a URL, listed as domains with the call on the same line (fetch,importScripts, a scriptsrc). Minified bundles and WebAssembly are named, because nobody can review them by eye. Each flag shows the file, the line number and the line. - The signatures it carries. For a .crx, CRX2 or CRX3, the keys in the header, which one the ID comes from and which belongs to another signer such as the Chrome Web Store. For an .xpi, the certificate Mozilla signed it with. Then every file, with its size; tap a script to read it as plain text.
What it cannot do
- It does not run or install the extension. Nothing in the file is executed, and the text view shows code as text.
- The code scan is a text search. Code built at run time from pieces, fetched from a server after install, or compiled into WebAssembly is not seen. A flag is a line to read, not a verdict: libraries such as lodash contain
Function(to find the global object, harmlessly. - Signatures are read, not verified. The ID comes from the key in the header, but whether that key really signed the file is left to Chrome and Firefox, which check it on install.
- It sees this version only. Extensions update themselves without asking. The file you check today is not a promise about next week's version.
- It does not look anything up. No store page, reputation list or malware scanner is consulted; nothing about the file leaves this tab.
Useful to know about extension files
- What a .crx and an .xpi are
- Both are ZIP archives of the extension's folder. A .crx (Chrome, Edge, Brave, Opera) puts a signed header in front of the ZIP: the bytes
Cr24, the format version (2, or 3 since Chrome 64 in 2018), then the public keys and signatures. An .xpi (Firefox) is a plain ZIP with Mozilla's signature files inMETA-INF/. Everything that matters is inmanifest.jsonat the top of the ZIP. - How the ID is made
- Chrome takes the SHA-256 hash of the developer's public key, keeps the first 16 bytes, and writes each of their 32 hex digits as a letter from a to p (0 is a, f is p). So a Chrome extension ID is always 32 letters from a to p, and anyone holding the key gets the same one. A CRX3 file also states the ID in its signed header; this page shows both and says whether they agree.
- Checking one you already run
- Chrome keeps installed extensions unpacked in its profile:
Extensions/<ID>/<version>/under%LOCALAPPDATA%\Google\Chrome\User Data\Default\on Windows,~/Library/Application Support/Google/Chrome/Default/on a Mac and~/.config/google-chrome/Default/on Linux. Zip that version folder and drop the ZIP here. Firefox keeps each add-on as<id>.xpiin theextensionsfolder of your profile (about:support, "Profile Folder"). - Getting the file from a store
- Stores install rather than download. On addons.mozilla.org, right-click "Add to Firefox" in another browser and save the link: that is the .xpi. For the Chrome Web Store, the file Chrome itself fetches is at
clients2.google.com/service/update2/crx?response=redirect&acceptformat=crx3&prodversion=130&x=id%3D<ID>%26ucwith the 32-letter ID in place of<ID>. - Why updates matter more than the first install
- An extension that was fine can turn bad in an update: in December 2024 attackers phished the Chrome Web Store login of Cyberhaven's developers and pushed a version that stole cookies and session tokens, and the same campaign hit dozens of other extensions. Earlier, in 2020, The Great Suspender was sold to a new owner and changed; Google removed it in 2021. Chrome installs updates silently, so an extension with
<all_urls>andcookiesis trusting its developer's account security as well as its developer. - Manifest V2 and V3
- Manifest V3 forbids code loaded from a server in an extension's own pages, replaces the background page with a service worker, and moves request blocking to rules the browser applies (
declarativeNetRequest). Chrome stopped running V2 extensions in 2025; Firefox runs both, and kept blockingwebRequest. V3 does not stop a content script from adding a remote script to the page you are on, which is why that is flagged too.