I ship eight small Chrome extensions under Legacy Tools. They are all
Manifest V3, and they all need some form of access to the pages you
visit — that is what tools that check things before you send them do.
I have written before about the rules I give AI agents
so they never broaden permissions on their own. This post is about the
other side of that: the shapes the declarations themselves take.
Recently I put all eight manifests side by side (the versions shipped to
the Chrome Web Store as of 2026-08-22) and realized they ended up using
four different shapes to declare that access. None of this was planned
up front; each shape fell out of what the tool is. Here is the survey.
The four shapes
1. Everywhere, all the time — five extensions.
Safe Privacy Gate, Safe Attachment Check, Safe Mail Link Check, Site
Operator Check, Find My Age. These step in right before a send or a
click, and there is no way to know in advance which site that will
happen on. Interesting detail: only two of the five actually write
<all_urls> into host_permissions. The other three get the same
breadth from content_scripts.matches alone.
2. One fixed site — one extension.
Safe Night Check is a Gmail-only tool, so the whole declaration is a
single pattern: https://mail.google.com/*.
3. A fixed list plus optional grants — one extension.
Safe Privacy Mask enumerates thirty matches patterns for the AI chat
sites it supports, and puts <all_urls> into
optional_host_permissions so that any other site is granted only when
the user adds it, one prompt at a time.
4. activeTab only — one extension.
Copy & Prep ships no content script at all. It touches only the tab
where you just ran its context-menu action. Standing access: zero.
The part that surprised me
While checking what these declarations look like from the user's side
(on chrome://extensions, with the extensions side-loaded into
Chromium), two things stood out:
-
The Permissions section came up empty every time. I measured
seven of the eight this way. Between them they use
storage,scripting,contextMenusandactiveTab— none of those produces a line in that box. "The permissions list is blank, so it must be harmless" is not a read you can make. -
matchescounts as a host permission. Safe Attachment Check declares nohost_permissionsat all, and its site-access wording was character-for-character identical to Safe Privacy Gate, which declares<all_urls>explicitly. You cannot shrink the warning by moving breadth out ofhost_permissionsand intocontent_scripts. - Bonus: the list shown to users is deduplicated. Mask declares thirty patterns; the screen shows fifteen. A short list does not mean narrow coverage.
What I take from this
Permission declarations are not configuration. They are UI — shown to
the user, in their words, at install time and on the details page. The
shape you choose is a product decision: <all_urls> is honest for a
tool that must work everywhere, a fixed list is honest for a
single-site tool, and activeTab is worth the extra design work when
"only when I ask" is the actual contract.
I wrote up the longer versions of both halves of this:
- The structure side — what runs where in a Manifest V3 extension, and how the manifest keys relate: https://legacy-tools.dev/en/notes/how-a-chrome-extension-works-manifest-v3/
- The display side — what the Permissions and Site access sections actually show, measured against our own manifests: https://legacy-tools.dev/en/notes/reading-chrome-extension-permissions/
Top comments (0)