Chrome Extension Review
Purpose
Review Chrome extensions for Manifest V3 compliance, security (CSP, XSS, privilege escalation), permission minimization, message-passing correctness, content script isolation, and Chrome Web Store policy readiness.
When to use
- Reviewing a new or updated Chrome extension before submitting to the Chrome Web Store.
- Auditing an existing extension's
manifest.json, service worker, content scripts, or popup pages. - Evaluating permission requests for least-privilege compliance.
- Reviewing extension code after a MV2 → MV3 migration.
- Security audit of an extension that handles user credentials, payment data, or PII.
When not to use
- Firefox/Safari WebExtension review where browser-specific APIs differ significantly — flag divergences but note this skill targets Chrome.
- Pure web app review with no
chrome.*API usage. - Native messaging host code review (separate OS-level process).
Procedure
1. Manifest V3 compliance
- Confirm
"manifest_version": 3— MV2 extensions are being phased out and will stop working in Chrome. background.service_workerreplacesbackground.scripts/background.pagefrom MV2.declarativeNetRequestreplaceswebRequestblocking mode — verify rules are defined in_rules.jsonor fetched viaupdateDynamicRules.actionreplacesbrowser_action/page_action.- Remote code execution is prohibited: no
eval(), nonew Function(string), nochrome.tabs.executeScriptwith a string body loaded from a remote URL. content_scriptsmust not usedocument.write().
2. Permissions — least privilege
- List every permission in
permissions,optional_permissions, andhost_permissions. - For each permission, verify it is actually used in the code. Remove any unused permission.
- Prefer
activeTabover broadhost_permissionslike<all_urls>or*://*/*when the extension only needs the current tab. - Sensitive permissions (
tabs,history,bookmarks,cookies,webNavigation,downloads,nativeMessaging) require clear justification in the store listing. scriptingpermission: verifychrome.scripting.executeScriptis not used to inject remotely-fetched code strings.storagevsunlimitedStorage: only requestunlimitedStorageif the data volume genuinely requires it.
3. Host permissions
- Scope to the minimum set of origins required.
https://api.example.com/*is better thanhttps://*/*. - Wildcard subdomains (
https://*.example.com/*) must be justified — ensure the extension does not accidentally run on all subdomains of a large service. - Optional host permissions should be requested at runtime via
chrome.permissions.request()rather than declared statically for permissions not needed at install time.
4. Content Security Policy
- Extension pages (popup, options, sidepanel) must have a strict CSP in
manifest.jsonunder"content_security_policy". - Minimum acceptable:
"script-src 'self'; object-src 'none';"— nounsafe-inline, nounsafe-eval. - External script sources in CSP are not allowed in MV3 for extension pages.
- Content scripts run in an isolated world by default; verify they do not access
unsafeWindoworwindow.wrappedJSObjectwithout necessity.
5. Message passing security
chrome.runtime.onMessage.addListener: verify thesenderis checked before acting on messages — do not trust messages from arbitrary web pages.chrome.runtime.sendMessagefrom content scripts: the service worker handler must validate the message shape before executing privileged actions.chrome.runtime.onMessageExternal(cross-extension messaging): explicitly whitelist allowed extension IDs if used.postMessagebetween content script and page: validateevent.originstrictly; never useorigin === '*'.
6. Content script isolation and XSS
- Content scripts must not inject innerHTML with page-supplied data:
element.innerHTML = response.datais XSS ifresponse.datais attacker-controlled. - Use
textContentfor text,createElement+setAttributefor DOM construction. - DOM-based XSS: watch for
document.location,document.URL,document.referrerfed intoeval,innerHTML, ordocument.write. - Content scripts should not expose functions on the page's
windowobject unless strictly necessary.
7. Service worker (background)
- Service workers are event-driven and terminate when idle — do not rely on in-memory state persisting between events; use
chrome.storage.sessionorchrome.storage.local. - Avoid long-running
setInterval— usechrome.alarmsfor periodic tasks. chrome.alarms.createrequires thealarmspermission.- Unhandled promise rejections in service workers silently fail — add
.catch()to all async chains. chrome.storage.localis not encrypted — do not store sensitive credentials there; usechrome.storage.session(cleared on browser restart) or the OS credential store via native messaging.
8. web_accessible_resources
- List only the resources that must be accessible from web pages.
- Specify
matchesto restrict which origins can access the resource — avoid"matches": ["<all_urls>"]. - An overly permissive
web_accessible_resourcesallows malicious pages to fingerprint extension presence and load extension assets.
9. Data handling and privacy
- Personal data collected (browsing history, form data, PII) must be disclosed in the store privacy policy and in the manifest
"privacy_policy"URL. - No sending of tab URLs or content to third-party servers without user consent.
- Verify no API keys, client secrets, or tokens are hardcoded in extension source — they are visible to users who inspect the extension.
10. Chrome Web Store policy readiness
- Extension must have a single, clear purpose described in the listing.
- No obfuscated code — the store may reject or remove extensions with intentionally obfuscated JavaScript.
- Update URL must be omitted (managed by the store) for public listings.
- Icons: 16, 48, 128 px PNG required; verify they are included in the package.
Checklist
MV3 compliance:
-
manifest_version: 3 -
background.service_workerdefined (nobackground.page) - No
eval(),new Function(string), or remote script injection -
declarativeNetRequestused instead of blockingwebRequestwhere applicable
Permissions:
- Every declared permission is used in code
-
activeTabpreferred over<all_urls>where possible - Sensitive permissions (
tabs,history,cookies) justified - Host permissions scoped to minimum required origins
Security:
- CSP on extension pages:
script-src 'self', nounsafe-inline/unsafe-eval -
runtime.onMessagevalidatessenderbefore privileged actions - Content scripts avoid
innerHTMLwith external data -
web_accessible_resourceshas restrictedmatches
Service worker:
- No in-memory state relied upon across events
-
chrome.alarmsused for periodic tasks, notsetInterval - All async promise chains have
.catch()
Privacy:
- No hardcoded API keys in source
- No PII sent to third parties without user consent
- Privacy policy URL in manifest
Common issues & anti-patterns
- MV2 background page left in manifest: causes load failure in Chrome 127+ (MV2 phase-out). Replace with
service_worker. "host_permissions": ["<all_urls>"]: flags for manual review in the store and is almost always broader than needed.innerHTMLwith data fromfetch(): if the fetched resource can be influenced by a web page (CORS, redirect), this is a stored XSS vector inside the extension context.- No
sendercheck inonMessage: a malicious web page can send crafted messages to the extension's background and trigger privileged actions. - Storing OAuth tokens in
chrome.storage.local: readable by any code with access to the extension context. Preferchrome.storage.sessionor prompt re-auth. eval()in content scripts for template rendering: violates MV3 CSP and the store policy.web_accessible_resources: ["*"]withmatches: ["<all_urls>"]: allows any web page to detect the extension and load any bundled asset.chrome.tabs.queryfor all tabs: collecting all open tab URLs is a privacy risk and requires justification; preferactiveTab.
Required output
Return a structured report with:
- Summary: pass / needs fixes / blocked (store-rejection risk or security issue).
- Manifest snapshot: key fields reviewed (version, permissions, host_permissions, CSP, service worker).
- Findings table: severity (critical / high / medium / low / info), category, file + line, description, remediation.
- Permission audit: each permission listed with justification status (justified / unused / overly broad).
- Store readiness: checklist of store policy items that pass or require attention.
- Next handoff: specific items to fix before store submission; note any that require store team waiver.
Safety
- Do not install or execute the extension in a browser during review.
- Never extract or print API keys found in the source — flag as critical finding requiring rotation.
- Do not access the extension's storage contents or user data.
- If the extension appears to perform undisclosed data collection (keylogging, form scraping), flag as critical and recommend immediate removal from distribution.