name: amo-compliance-check description: Use when checking a Firefox extension for addons.mozilla.org (AMO) submission compliance, before packaging or publishing a Firefox WebExtension. Trigger on "AMO rejected my addon", "prep this addon for mozilla", "check firefox extension for AMO", "is this extension signable", "will AMO accept this manifest", "amo compliance".
AMO Compliance Check
Systematic review of a Firefox extension against addons.mozilla.org submission requirements.
Instructions
When invoked, identify the extension root directory (the directory containing manifest.json for the Firefox/Mozilla version). If unclear, ask the user.
Preferred — run the bundled script first:
skills/amo-compliance-check/scripts/amo-check.py <extension-dir>
It runs sections 1–8 and 10 automatically: manifest parse + required/conditional field validation (regex for version and gecko.id), icon-file existence + SVG attribute check, hidden/binary/case-duplicate scan, referenced-file existence, permission validation against the AMO-allowed set, remote-script and eval/new Function/string-timer detection, CSP unsafe-eval check, cryptominer references, and HTTP (non-HTTPS) URL scan. Output is per-finding lines plus the summary table. Exit 1 if any FAIL was found.
Determinism boundary. The mechanical AMO/manifest checks above are also exposed on the plugin-dev shared finding contract via
${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh(which runsvalidate-amo.sh, a thin wrapper overamo-check.py). Runbash ${CLAUDE_PLUGIN_ROOT}/scripts/validate.sh --json(orvalidate-amo.sh <extension-dir> --json) when you want structured findings. Obfuscation/minification detection and permission-necessity judgment stay in this LLM lane — the script only flags the decidable parts.
After the script, still read the sections below — they are the source of truth for what's checked and cover the pieces that need human judgment: section 5 (is <all_urls> actually necessary?), section 7 (obfuscation/minification patterns), section 9 (content-script DOM-injection safety), and MV3 data_collection_permissions values. Use the numbered sections as both the script's spec and your manual-pass checklist.
Manual pass (fallback — only if the script isn't available)
Run every check below in order. For each section, report PASS, WARN, or FAIL with a brief explanation. At the end, provide a summary table.
1. Manifest — Required Fields
Read manifest.json and verify:
-
manifest_versionexists and is2or3 -
nameexists, is non-empty, no leading/trailing whitespace, max 50 characters -
versionexists and matches^(0|[1-9][0-9]{0,8})([.](0|[1-9][0-9]{0,8})){0,3}$
2. Manifest — Conditional & Recommended Fields
- If
_locales/directory exists,default_localemust be set. If no_locales/,default_localemust be absent - For MV3:
browser_specific_settings.gecko.idis present (required for AMO). For MV2: recommended - Extension ID format is valid: email-like (
^[a-zA-Z0-9-._]*@[a-zA-Z0-9-._]+$, max 80 chars) or GUID (^\{[0-9a-fA-F]{8}-...}$) -
descriptionis present and max 132 characters -
homepage_urldoes NOT link to addons.mozilla.org -
update_urlis NOT present (forbidden for AMO-hosted extensions) -
applicationskey is not used (deprecated; usebrowser_specific_settings). Invalid in MV3 - If
strict_min_versionis set, it does not use*wildcard - No block comments (
/* */) in JSON. No duplicate keys
3. Icons
- All icon files referenced in manifest exist on disk
- Icon files are PNG or SVG (valid extensions)
- At minimum 48px and 96px icons are provided (recommended for AMO listing)
- SVG icons (if any) include
viewBoxandxmlnsattributes
4. File Structure
- No hidden files (dotfiles) in the extension directory
- No flagged binary extensions (
.exe,.dll,.so,.dylib,.bin) - No duplicate filenames that differ only by case
- All files referenced in
content_scriptsexist and have non-empty filenames - All files referenced in
background.scriptsorbackground.pageexist - All files referenced in
web_accessible_resourcesexist
5. Permissions
- Only valid WebExtension permissions are requested
- No privileged/Mozilla-internal permissions (
mozillaAddons, etc.) -
<all_urls>or broad host permissions — flag as WARN (requires justification) - Permissions appear necessary for the extension's stated functionality (flag unnecessary ones)
6. Security — No Remote Code
- No
<script src="http...">or<script src="//...">tags in HTML files (remote script loading) - No
fetch()/XMLHttpRequestcalls that load JS for execution (eval of fetched code) - No
eval(),new Function(),setTimeout(string),setInterval(string)in JS files - No
document.write()usage - If
content_security_policyis customized, it does NOT containunsafe-eval
7. Security — Code Quality
- No obfuscated code (check for common obfuscation patterns: long hex strings,
\xescape sequences in bulk, base64-encoded blocks executed via eval) - No minified code without source submission (WARN if code appears minified)
- No cryptocurrency mining patterns (
CoinHive,coinhive,crypto-loot, miner references)
8. Data & Privacy
- If extension transmits any user data remotely, a privacy policy URL should be noted as required for AMO listing
- All remote requests use HTTPS, not HTTP
- No data storage patterns in private browsing context (check for
incognitohandling)
9. Content Scripts & Web Page Security
- Content scripts do not relax or modify page CSP
- Content scripts properly sanitize any DOM injection (no raw
innerHTMLwith unsanitized external data)
10. Manifest V3 Specific (if applicable)
-
background.service_workerhas abackground.scriptsfallback for Firefox compatibility -
incognitois not set to"split"(unsupported in Firefox) -
browser_specific_settings.gecko.data_collection_permissionsis present with valid values
Summary Format
After all checks, output a table:
| Section | Status | Issues |
|----------------------------|--------|--------|
| Manifest Required Fields | PASS | |
| Manifest Conditional | WARN | ... |
| Icons | PASS | |
| File Structure | PASS | |
| Permissions | WARN | ... |
| Security — Remote Code | PASS | |
| Security — Code Quality | PASS | |
| Data & Privacy | PASS | |
| Content Scripts | PASS | |
| MV3 Specific | N/A | |
Then list actionable items sorted by severity (FAIL first, then WARN).
Delegation (Claude Code only)
Skip this section unless you are Claude Code. The Agent tool with
subagent_type:parameters is a Claude Code feature. Codex, Cursor, Gemini, OpenCode, and other hosts do not have it — run the full workflow yourself instead.
The manifest read, the permission enumeration, the web-ext lint run, and the
file/structure checks are all read-only bulk I/O. If you are running on Opus and
the extension is non-trivial, delegate the scan phase to the readonly-scanner
subagent (model: haiku) via the Agent tool with subagent_type: readonly-scanner.
Give it the extension root path and ask it to return:
manifest.jsonparsed, with all fields relevant to AMO policy.- The permission list, any host permissions, and which scripts declare them.
web-ext lint --output=jsonraw output ifweb-extis on PATH.- File tree summary (size, count, flagged binary/minified files).
Integrate those findings into the compliance verdict yourself — the verdict itself stays with the caller.