Arguments:
[path] [--strict] [--json]. Wherever<arguments>appears below, substitute the text the user typed after the skill name.
Firefox Extension Lint
Comprehensive pre-publish lint for a Firefox WebExtension.
CRITICAL RULES
- Run
web-ext lintfirst -- Mozilla's official linter catches AMO-blocking issues (remote code, missing icons, invalid manifest). - Then scan source for anti-patterns that
web-ext lintmisses: eval/Function, remote script injection, wildcards in host_permissions, stored tokens in non-session storage. - Report results grouped by severity matching AMO's own review criteria.
Procedure
1. Run web-ext lint
cd "$TARGET"
npx web-ext lint --pretty
Parse the output. If --json flag set, use --output=json and parse JSON.
2. Static checks beyond web-ext lint
Run these greps / AST checks against src/:
Forbidden / high-risk APIs (AMO review often rejects)
eval(,new Function(-- AMO blocks unless justifieddocument.write(-- CSP violationinnerHTML =with user-controlled input -- XSS risk- Remote script loading:
<script src="https://...">in extension pages browser.tabs.executeScriptwith dynamic code strings (MV2)
Permission bloat
<all_urls>inhost_permissions-- AMO reviewers ask "why?""tabs"permission without reading tab URL/title/favIcon (often over-requested)"storage"permission without anybrowser.storage.*call (dead permission)"webNavigation"withoutonBeforeNavigate/onCompletedlisteners
Auth / storage anti-patterns
- Tokens / API keys in
localStorage(persists, shared with content scripts ifall_frames) - Secrets hardcoded in source
browser.storage.localfor secrets -- acceptable but document the trust boundary
Manifest V3 migration issues (if MV3)
browser.webRequest.onBeforeRequestwith["blocking"]-- MV3 removed blocking webRequest on Chrome; Firefox still supports it but discourage for cross-browser- Service worker / event page confusion -- Firefox MV3 uses event pages (DOM access OK), Chrome MV3 uses service workers
- Missing
declarativeNetRequestrules when webRequest is being deprecated
Code quality
console.login production code- No
"strict_min_version"inbrowser_specific_settings.gecko(makes update channel unclear) - Extension ID collisions / placeholder IDs
3. Output format
# Firefox Extension Lint -- <extension-name> -- <date>
## Summary
- [BLOCKER] (AMO will reject): N
- [WARNING]: N
- [INFO]: N
## Blockers
- <file:line> <issue> -- <AMO rule or CVE> -- <fix>
- ...
## Warnings
- ...
## Informational
- ...
## Permissions audit
| Permission | Declared | Used | Recommendation |
|-----------|----------|------|----------------|
| `<all_urls>` | yes | <file:line>... | Narrow to specific domains |
| `tabs` | yes | - | Remove (unused) |
| ... |
## Next steps
1. Fix blockers
2. Run `npm run build` to produce the signed .zip
3. Run `/browser-extensions:firefox-publish` to sign + upload via AMO API
With --strict, treat all warnings as blockers (exit code 1).
Synergies
- Full API / manifest details ->
browser-extensions:firefox-extension-devagent - Pre-AMO publishing workflow ->
/browser-extensions:firefox-publish - New extension scaffolding ->
/browser-extensions:firefox-scaffold