Ten names that look like Chrome extension permissions and are not

Written 8 August 2026, checked against the official Chrome permissions list the same day. Permanent copy on Arweave.

A Chrome extension declares what it wants in the permissions array of manifest.json, and that array is most of what a user is shown before installing. So any checklist, audit sheet or risk table that reasons about extension permissions is only as good as its list of names. A row naming something Chrome does not implement cannot be wrong in an interesting way. It is not describing anything.

I had a 68-row permission table to audit and decided to check the names before the judgements, because the names are the part with an authority behind them. Chrome publishes the complete list at developer.chrome.com/docs/extensions/reference/permissions-list. Extracting every quoted permission name from that page on 8 August 2026 gives 78 entries. Comparing against it is a set membership test; there is nothing clever to get right.

Ten of the 68 names were not on the list. They are not typos. They fail in four distinct ways, and each way is a mistake that can be made again.

The heuristic that does not work

The tempting shortcut is to treat a dotted name as suspect: storage.session has a dot in it, so it must be an API path rather than a permission. That heuristic is wrong often enough to be dangerous. Thirteen of the 78 official names contain a dot:

accessibilityFeatures.modify     enterprise.networkingAttributes
accessibilityFeatures.read       enterprise.platformKeys
downloads.open                   identity.email
downloads.ui                     system.cpu
enterprise.deviceAttributes      system.display
enterprise.hardwarePlatform      system.memory
                                 system.storage

downloads.open is a real permission and downloads.shelf is not, and nothing in the shape of either string tells you which is which. That is the actual finding: no syntactic rule separates a permission from a plausible non-permission, which is exactly why the check has to be mechanical rather than by eye.

Failure mode 1: an API surface mistaken for a permission

Name in the tableWhat it actually is
storage.sessiona StorageArea exposed as a property of chrome.storage
storage.managedthe same, for values pushed by enterprise policy
storage.accessednot a documented storage area either
windowsan API namespace, chrome.windows, gated by a differently-named permission

The storage areas are real and they behave differently from one another, so a document describing them describes something true. But the manifest permission that unlocks all of them is the single string storage, which is what the official list carries. Splitting one permission into three rows makes an extension look like it is asking for more than it is, and it makes any total over the table meaningless.

windows is the more instructive case, because the official list answers it directly in the entry for tabs:

"tabs" — Gives access to privileged fields of the Tab objects used by several APIs, including chrome.tabs and chrome.windows. You usually don't need to declare this permission to use those APIs.

So window management is not gated by a windows permission; the privileged fields are gated by tabs, and the ordinary parts of the API need no declaration at all. A table with a windows row has invented a permission boundary that does not exist, and by doing so it hides the one that does.

Failure mode 2: an invented sibling of a real name

Name in the tableThe real siblings on the official list
downloads.shelfdownloads, downloads.open, downloads.ui
system.networksystem.cpu, system.display, system.memory, system.storage
wallpaper.legacywallpaper

This is the mode that survives review, because each invented name sits inside a family that genuinely has members. system.cpu and system.memory exist, so system.network reads as the obvious fourth. It is not there. Neither is downloads.shelf, in a family where two dotted siblings do exist.

Failure mode 3: a manifest key mistaken for a permission

commands and host_permissions are both top-level keys in manifest.json. Neither appears anywhere on the permissions list.

host_permissions is the consequential one, because it is where the broad access actually lives. A manifest asking for <all_urls> asks in host_permissions, not in permissions. A table that files host_permissions as one permission among 68 has flattened the most important axis of extension risk — which sites the extension may touch — into a single row sitting next to idle and alarms. That is not a naming slip. It means the model of the manifest is wrong.

Failure mode 4: a permission from a different platform

fileSystem is real, and it is not an extension permission. It belongs to the Chrome Apps platform, which is retired. The extensions list carries no fileSystem entry at all; the nearest names on it are fileSystemProvider, for implementing a virtual file system, and fileBrowserHandler, for handling files opened from the ChromeOS file browser. Both are narrower things wearing a similar name.

This one is worth separating from the invented names because the failure is different in kind. The name has a real referent and correct documentation somewhere, so every check short of "is it on this specific list" passes it. Searching for it finds a genuine API reference. Only the set comparison catches it.

The check, and what it caught that reading did not

Extract the quoted names from the official list, extract the names from whatever you are auditing, take the difference. On 8 August 2026 the first half returned 78 names:

curl -s https://developer.chrome.com/docs/extensions/reference/permissions-list \
  | grep -oE '&quot;[a-zA-Z][a-zA-Z0-9._]*&quot;</code>' \
  | sort -u

The table I was auditing had already been reviewed by hand, and that review reported eight bad names. Running the set difference returned ten. The two it had missed were windows and fileSystem — precisely the two that do not look wrong, because both name real things. Every name that was caught by eye was caught because it looked odd, and both names that looked reasonable survived. An eyeball pass over a list of 68 plausible identifiers finds the ugly errors and leaves the well-dressed ones in place.

Two caveats on the result. The official list changes as permissions are added and removed across Chrome releases, so a count is a snapshot with a date on it, not a constant. And the list deliberately excludes host permissions, because those live under a separate manifest key — an audit that wants to describe what an extension can actually reach has to read host_permissions and the content_scripts match patterns as their own question.

Why this is worth the ten minutes

Permissions are the only pre-install signal most people get. The install dialog paraphrases them into sentences like "Read your browsing history", and that paraphrase is generated from what the manifest declares — the official list prints the exact warning string next to the permissions that trigger one. A reviewer working from a checklist containing names Chrome does not implement will watch for warnings that can never fire, while the field that decides the blast radius has been mis-filed as an ordinary row.

The defensible version of a permission audit is boring. Take the manifest, intersect its permissions array with the official list, report anything outside the intersection as undocumented rather than as safe, and treat host_permissions as a separate question with its own answer. Any risk weighting layered on top is editorial judgement and should be labelled as such, because there is no measurement behind scoring tabs at 72 out of 100.