crx-manifest-parser
Parse a Chrome / Chromium Manifest V3 manifest.json string into a
strongly-typed Manifest struct
exposing the fields an extension security scanner actually cares about:
name,version,description,manifest_versionpermissionsandoptional_permissions(named API tokens)host_permissions(match-patterns granting site access)content_scripts(the script + match list — the biggest cross-origin exposure surface)
Pure Rust, zero dependencies (no serde, no serde_json), #![forbid(unsafe_code)].
Ships its own minimal, fully-tested JSON value parser so a manifest can be
decoded without dragging a JSON library into the build graph.
This is the manifest-decode layer behind the zovo.one Chrome-extension privacy & security scanner, which audits the permissions requested by any installed extension and flags the ones that can read your data across every site.
Why parse the manifest
The manifest.json is the single source of truth for what an extension is
allowed to do. Two extensions that both "just change your new tab page" can
declare wildly different access: one asks for storage, the other for
<all_urls> + cookies + content scripts on every site. The manifest is the
first thing a privacy review opens — this crate turns it into a typed value
you can branch on, render, or feed to a permission auditor (see the
companion permission-auditor
crate).
Install
[]
= "0.1"
Quick start
use Manifest;
let json = r#"{
"manifest_version": 3,
"name": "My Extension",
"version": "1.4.2",
"permissions": ["activeTab", "storage"],
"host_permissions": ["https://*.example.com/*"],
"content_scripts": [
{ "matches": ["https://*.example.com/*"], "js": ["content.js"] }
]
}"#;
let manifest = from_json.expect;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert_eq!;
assert!;
// The full set of grant tokens, ready for a permission auditor.
assert_eq!;
API surface
| Item | Description |
|---|---|
Manifest |
Typed struct over the security-relevant fields. |
ContentScript |
One content_scripts entry (matches, js, css, ...). |
Manifest::from_json(s) |
Parse a manifest string into a Manifest. |
Manifest::from_json_value(&v) |
Build from an already-parsed Json value. |
Manifest::all_grants() |
permissions + host_permissions concatenated. |
Manifest::content_match_patterns() |
Deduped site match-patterns across all content scripts. |
Manifest::is_mv3() / is_mv2() |
Manifest-version predicates. |
Json, ParseError |
The bundled JSON value model + parse error. |
Design choices
- Zero dependencies. No
serde, noserde_json. The crate carries a small recursive-descent JSON parser so it works in any sandboxed or constrained build context. - Missing fields are tolerated. Manifests routinely omit keys; a missing
permissionsarray is an emptyVec, not an error. A parse error only fires for malformed JSON or a field with the wrong JSON type (e.g.permissionsgiven as a string). - No
unsafe.#![forbid(unsafe_code)]— there is no unsafe anywhere in the crate. - UTF-8 and escape fidelity. Strings are decoded with full
\uXXXX/ surrogate-pair /\b \f \n \r \thandling, and raw control characters are rejected (per RFC 8259) so a manifest can't smuggle unescaped control bytes.
License
MIT.
Links
- zovo.one — the Chrome-extension privacy & security scanner that uses this parser: https://zovo.one/
- Source (zovo monorepo): https://github.com/theluckystrike/zovo
- Full API docs: https://docs.rs/crx-manifest-parser