Paste one browser extension manifest.json and a list of concrete URLs.
This page parses every match pattern in the manifest, resolves each URL against each pattern bearing
key independently, and prints, per key, whether the URL is granted and via exactly which pattern.
Nothing is uploaded. There is no score and no advice.
The same match pattern resolves differently depending on which manifest key it sits in. Two flags do all the work: whether the path is matched or ignored, and which URL schemes the key accepts. This table is the reference value of the tool, so it is rendered before you paste anything.
| Manifest key | Path | Schemes accepted | Source |
|---|---|---|---|
| host_permissions | ignored | chrome, http, https, file, ftp, ws, wss, uuid-in-package | permissions_parser.cc:150 to :152 forces the path to /* after a successful parse. Mask from extension.cc:217 to :221. |
| optional_host_permissions | ignored | chrome, http, https, file, ftp, ws, wss, uuid-in-package | Same code path, permissions_parser.cc:440 to :447 calls the same parser for both keys. |
| content_scripts[].matches | matched as a glob | chrome, http, https, file, ftp, uuid-in-package | user_script.cc:69 to :73, narrowed at :109 to :118. |
| content_scripts[].exclude_matches | matched as a glob | chrome, http, https, file, ftp, uuid-in-package | Same mask as the matches list it sits beside. |
| externally_connectable.matches | matched as a glob | any scheme | externally_connectable.cc:108 constructs the pattern with SCHEME_ALL. |
| web_accessible_resources[].matches | must be exactly /* |
any scheme | web_accessible_resources_info.cc:120 constructs the pattern with SCHEME_ALL, and :121 to
:124 reject the whole manifest unless pattern.path() is exactly /*. |
A wildcard scheme is a separate rule that overrides the column above: * narrows to
http or https in every key, including the two that otherwise accept any
scheme, because SetScheme intersects the mask down to those two the moment it sees
*.
activeTab, optional permissions the user has actually granted, chrome.scripting injections registered at runtime, or declarative net request rules.CanSpecifyHostPermission check that turns some host permissions into install warnings.127.1. Chromium does all three. Patterns and URLs that depend on those will resolve differently here, so this tool refuses to be the last word on them.When a manifest declares web_accessible_resources, the matches list is
not the only exit. Under manifest version 3 the resolution is
entry.matches.MatchesURL(initiator_url) inside
IsResourceWebAccessibleImpl, at web_accessible_resources_info.cc:231, and the function
returns false when nothing matches. The other ways through are a
chrome-extension:// initiator via allow_all_extensions or a listed
extension_ids entry, and the legacy bypass at :199 to :201, which applies only when
manifest_version is below 3. This page prints all of them beside the entry rather than
implying matches is the whole gate.
What this page reports is which pages may load your extension's files. It does not compute a fingerprinting verdict. The reason the default is empty is worth reading in the documentation's own words, once, as a quotation and not as this tool's output:
"By default no resources are web accessible, as this allows a malicious website to fingerprint extensions that a user has installed or exploit vulnerabilities (for example XSS bugs) in installed extensions." Chrome for Developers, web_accessible_resources reference. The same page states: "A navigation from a web origin to an extension resource is blocked unless the resource is listed as web accessible."
A match pattern has four components, not three. The documentation gives the structure as
<scheme>://<host>:<port>/<path> and states that the port is
optional and "By default, this is treated as a wildcard with the same behavior as :*",
and that "Match patterns match all ports unless an explicit port is specified."
The ordering inside the parser is the part that a three component implementation gets wrong. The
port is split off the authority before the host wildcard rule is applied. Chromium finds the
: separator inside host_and_port at url_pattern.cc:269 to :300 and only
then validates the host, and MatchesPortPattern at :907 is the whole of the port
comparison: return port_ == "*" || port_ == port;. Validate the host first and
http://*:*/* dies with a host wildcard error, taking every explicit port pattern with
it. That row is in the self test above, and so is the Chromium test case
http://fo.*.ba:123/baz, which reports a host wildcard error only if the port was
removed first.
Three more rules that surprise people, all verified against the source rather than the prose:
URLPattern::SetPath at url_pattern.cc:407 does no
expansion, so https://*/ matches the path / and nothing else. The
documented claim that such a pattern "matches any URL using the https scheme" holds under
host_permissions, where the path is discarded, and does not hold under
content_scripts, where it is matched. That split is per key, and this page shows both
answers rather than picking one.IsValidPortForScheme at
url_pattern.cc:98 to :113 rejects any non wildcard port when
url::DefaultPortForScheme returns unspecified, and that function, at
url_canon_stdurl.cc:122 to :148, knows only http, https, ftp, ws and wss. The wildcard scheme
* is not among them, so *://example.com:8443/* is rejected as an invalid
port. Write https://example.com:8443/* instead.GURL::PathForRequest(), so /a/../b has already become /b,
a backslash has already become a forward slash, a space has already become %20,
and a tab, carriage return or line feed has already been deleted outright rather than encoded,
by the time the glob sees it. This page does the same four things, so
https://example.com/b* grants https://example.com/a/../b here exactly
as it does in Chrome. Matching the raw text instead prints a confident "no match" for a URL the
manifest really grants, which is the fail open direction.Every line number on this page was read from the file it names, in the main branch, on 2026-09-08. Line numbers move as the branch moves; the function names do not.
Independent and unaffiliated with Google, Chromium or any browser vendor. Behaviour was reimplemented from the published specifications and source listed above. No third party code is reproduced here. MIT licensed, Copyright (c) 2026 0xelitesystem. Built by elitesystem.ai