How to design a Chrome Extension from the ground up with full security discipline, and link it with specs, source code, and browser internals. 🧠⚙️
1. Threat Model for Chrome Extensions
First, understand how extensions are attacked:
Threat | Example |
---|---|
Privilege Escalation | Extension gets too much permission, used by attacker |
XSS in Extension Pages | Popup.html vulnerable to script injection |
Message Forgery | Untrusted websites sending forged chrome.runtime.sendMessage() |
Content Script Injection | Content scripts leaking sensitive page data |
Manifest Spoofing / Typosquatting | User installs malicious extension |
Supply Chain Attacks | 3rd party libraries embedded insecurely |
2. Security Critical Features To Design Carefully
2.1. Minimal manifest.json
Permissions
What:
Grant only the absolute minimum permissions.
Origin:
Example (bad):
{
"permissions": ["tabs", "storage", "cookies", "webRequest", "*://*/"]
}
→ Huge attack surface!
Example (good):
{
"permissions": ["storage"],
"host_permissions": ["https://your-site.example.com/*"]
}
Chain to Source Code:
-
Chromium: Permission Parsing
PermissionsData::HasAPIPermission() PermissionsData::HasHostPermission()
-
Decides runtime access control for API calls.
2.2. Isolate Content Scripts Properly
What:
- Content scripts run in the context of the target web page but are isolated via an isolated world.
Risk:
- Content script can leak secrets from page or be attacked by page scripts.
Secure Handling:
- Always treat DOM inputs as untrusted.
- Use messaging to background scripts to handle privileged actions.
Spec Reference:
Chain to Source Code:
-
Chromium: Content script injection mechanism
content_scripts
injected throughUserScriptSet::InjectScripts()
.
2.3. Use Strict CSP (Content Security Policy)
What:
- Extensions must enforce a strict CSP to prevent XSS inside their own pages (popup.html, options.html, etc.)
Default MV3 CSP:
Content-Security-Policy: script-src 'self'; object-src 'self'
Secure Customizations:
- Avoid
unsafe-inline
- Avoid remote script loads.
Spec Reference:
Chain to Source Code:
-
Chromium: CSP header application
Applied automatically during extension frame navigation setup.
2.4. Secure Messaging (chrome.runtime.sendMessage)
What:
- Extensions use
chrome.runtime.sendMessage
orchrome.runtime.onMessage
to pass messages internally or from web pages.
Risk:
- External sites can spoof messages if listeners are poorly validated.
Best Practices:
- Validate sender inside
onMessage
. - Use
chrome.runtime.connect
with ports if needed for more structured communications.
Example:
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (sender.origin !== 'https://trusted.example.com') {
return;
}
// process message safely
});
Spec Reference:
Chain to Source Code:
-
Chromium: chrome.runtime.onMessage dispatcher
MessageService::DispatchMessage()
checks internal permissions.
2.5. Background Scripts in MV3 (Service Workers)
What:
- MV3 replaces persistent background pages with background service workers.
Security Benefit:
- Service workers have no DOM access.
- Lifetime is limited — reduces long-term attack surface.
Important:
- Handle message passing asynchronously.
- Revalidate everything on fresh service worker startup.
Spec Reference:
2.6. Declarative Net Request API
What:
- MV3 extensions should use declarativeNetRequest instead of
webRequest
where possible.
Security Win:
- No access to raw network request data.
- Only declarative rules.
- Harder to leak data or manipulate unauthorizedly.
Example:
"declarative_net_request": {
"rule_resources": [{
"id": "ruleset_1",
"enabled": true,
"path": "rules.json"
}]
}
Spec Reference:
2.7. Web Accessible Resources Restrictions
What:
- Extensions can declare which internal files are visible to external websites.
Secure Usage:
- Avoid making sensitive resources (
popup.html
,background.js
) web-accessible unless absolutely necessary.
Example:
"web_accessible_resources": [
{
"resources": ["image1.png"],
"matches": ["https://trusted.example.com/*"]
}
]
Chain to Source Code:
- Chromium: Web Accessible Resources enforcement
2.8. Extension Origin Isolation
What:
- Extensions run under
chrome-extension://<uuid>/
origins.
Risk:
- If web pages link to extension resources improperly, data leaks can occur.
Mitigations:
- Use strict
CSP
. - Limit
web_accessible_resources
. - Validate extension ID origin inside communications.
3. Bonus: Browser Internal Security Protections
Protection | How It Works | Chromium Code Link |
---|---|---|
Site Isolation | Extensions render separately from webpages | //content/browser/site_per_process/ |
Origin Trials | Control features via opt-ins | //content/browser/origin_trials/ |
Sandboxing Extension Processes | Each extension gets a low-privilege renderer | //extensions/renderer/ |
4. Full Security Checklist for Extension Development
✅ Use MV3 Service Workers (no background page)
✅ Minimal permissions in manifest.json
✅ Strict CSP (script-src 'self'
)
✅ Content scripts isolated from page
✅ Validate all chrome.runtime
message origins
✅ Limit web accessible resources
✅ No remote code (no eval, no remote scripts)
✅ Use declarativeNetRequest
instead of webRequest
✅ Audit and freeze external libraries (npm, etc.)
✅ Follow defense-in-depth (assume compromise possible at every boundary)
5. Final Offer
If you want, I can go one level deeper:
- Trace real-world extension attacks like DataSpii, Augury and show you where they failed on each of these points.
- Show extension lifecycle internals (extension loading → permission granting → renderer spawning flow inside Chromium).
- Real examples of secure extension projects you can reference.