| name | browser-extension-pentest |
| description | Security testing methodology for browser extensions (Chrome, Firefox, Chromium). Use this skill whenever you need to audit, analyze, or pentest a browser extension for vulnerabilities. Trigger this skill for extension security reviews, manifest.json analysis, content script vulnerability assessment, native messaging security checks, or when investigating extension-based attacks. Don't forget to use this skill for any browser extension security work, even if the user doesn't explicitly mention "pentesting" or "security audit". |
Browser Extension Pentesting Methodology
A comprehensive guide for security testing browser extensions across Chrome, Firefox, and Chromium-based browsers.
Quick Start
- Get the extension source (see Getting Source Code)
- Analyze manifest.json for permissions and attack surface
- Review content scripts for DOM-based vulnerabilities
- Check background scripts for message handling issues
- Test native messaging if present
- Run the security checklist
Getting Source Code
From Chrome Web Store (by Extension ID)
extension_id="YOUR_EXTENSION_ID"
curl -L -o "$extension_id.crx" "https://clients2.google.com/service/update2/crx?response=redirect&os=mac&arch=x86-64&nacl_arch=x86-64&prod=chromecrx&prodchannel=stable&prodversion=44.0.2403.130&x=id%3D$extension_id%26uc"
mv "$extension_id.crx" "$extension_id.zip"
unzip -d "$extension_id-source" "$extension_id.zip"
Alternative Methods
- CRX Viewer website: https://robwu.nl/crxviewer/
- CRX Viewer extension: Install from Chrome Web Store
- Local profile: Navigate to
chrome://version/ → Profile Path → Extensions/ folder
- File archiver: Rename
.crx to .zip and extract
Load Unpacked Extension
Chrome: chrome://extensions/ → Enable Developer Mode → Load unpacked
Firefox: about:debugging#/runtime/this-firefox → Load Temporary Add-on
Extension Architecture
Browser extensions have three main components with strong isolation boundaries:
Content Scripts
- Access: Direct DOM access to single web page
- Risk: Exposed to potentially malicious input from the page
- Permissions: Limited to sending messages to extension core
- Isolation: Runs in separate JavaScript heap from web page
Extension Core (Background)
- Access: Most extension privileges
- Communication: XMLHttpRequest and content scripts only
- Persistence: Runs continuously in background
- No direct host machine access
Native Binary
- Access: Full user privileges on host machine
- Communication: NPAPI with extension core
- Risk: Critical if compromised (RCE possible)
Manifest.json Analysis
The manifest.json is the extension's configuration file. Analyze these key fields:
Permissions
{
"permissions": ["storage", "tabs", "nativeMessaging"],
"host_permissions": ["https://*.example.com/*"]
}
Check for excessive permissions:
nativeMessaging - Can communicate with native binaries (RCE risk)
tabs - Can access all tab data
cookies - Can read all cookies
webRequest - Can intercept/modify network requests
storage - Can access extension storage
Content Scripts
"content_scripts": [
{
"js": ["script.js"],
"matches": ["https://example.com/*"],
"exclude_matches": ["*://*/*business*"],
"run_at": "document_idle"
}
]
Key fields:
matches - URLs where script injects (wider = more attack surface)
run_at - When script runs (document_start, document_end, document_idle)
js - JavaScript files to inject
Web Accessible Resources
"web_accessible_resources": [
{
"resources": ["images/*.png"],
"matches": ["https://example.com/*"]
}
]
Risk: Pages listed here can be accessed via chrome-extension://<extension-id>/page.html and may be vulnerable to:
- ClickJacking (check CSP
frame-ancestors)
- XSS if the page processes user input
Externally Connectable
"externally_connectable": {
"matches": ["https://*.google.com/*"]
}
Critical: If a vulnerable web page is listed here, attackers can:
- Send messages directly to background script
- Bypass content script and CSP protections
- This is a very powerful bypass
Best practice: Use {} if no external connections needed
Content Security Policy
"content_security_policy": "script-src 'self'; object-src 'self';"
Default is restrictive but check for:
- Whitelisted CDNs that could be compromised
unsafe-inline or unsafe-eval directives
- Missing
frame-ancestors for web_accessible_resources
Communication Patterns
Web Page ↔ Content Script
PostMessage (most common):
window.postMessage({ type: "FROM_PAGE", text: "data" }, "*")
window.addEventListener("message", (event) => {
if (event.source !== window) return
if (event.data.type === "FROM_PAGE") {
}
})
Security checks needed:
event.isTrusted - Verify user action triggered it
event.origin - Validate sender domain
event.source !== window - Check same window
Content Script ↔ Background Script
chrome.runtime.sendMessage({ greeting: "hello" })
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.greeting === "hello") {
sendResponse({ farewell: "goodbye" })
}
})
For async responses, return true from the listener:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
setTimeout(() => {
sendResponse({ result: "done" })
}, 1000)
return true
})
Native Messaging
chrome.runtime.sendNativeMessage(
"com.my_company.my_application",
{ text: "Hello" },
(response) => console.log(response)
)
Native host JSON (installed on system):
{
"name": "com.my_company.my_application",
"path": "/path/to/binary",
"type": "stdio",
"allowed_origins": ["chrome-extension://<extension-id>/"]
}
Critical vulnerability pattern:
- Content script has wildcard URL match
- Content script forwards
postMessage to background via sendMessage
- Background forwards to native app via
sendNativeMessage
- Native app processes input unsafely → RCE
Vulnerability Testing
DOM-Based XSS
Content scripts trust the DOM. If the web page can modify DOM elements the content script reads:
const data = document.getElementById("user-input").textContent
chrome.runtime.sendMessage({ data: data })
Test: Inject XSS into page elements the extension reads
PostMessage Bypasses
Check for:
- Missing origin validation
- Overly broad
"*" target
- Regex-based domain validation (can be bypassed)
- Missing
event.isTrusted check
ClickJacking
For web_accessible_resources pages:
- Check CSP for
frame-ancestors directive
- Try loading in iframe:
<iframe src="chrome-extension://<id>/page.html"></iframe>
- If loads, test UI overlay attacks
Information Disclosure
Memory: Sensitive data in extension memory can be dumped:
- Chrome DevTools → Memory tab → Take snapshot → Search
- Process memory dumps (Windows)
Code: Never store secrets in extension code (publicly visible)
Clipboard: Sensitive data copied to clipboard can be monitored
Security Audit Checklist
Use this checklist for every extension audit:
Tools
Tarnish
https://thehackerblog.com/tarnish/
Features:
- Manifest.json viewer
- Web accessible resources detection
- ClickJacking analysis
- Dangerous function detection (innerHTML, executeScript)
- Entry point identification
- CSP analyzer and bypass checker
- Known vulnerable library detection (Retire.js)
Neto
https://github.com/elevenpaths/neto
Python package for analyzing browser extensions:
- Extracts features from manifest.json
- Parses JavaScript and HTML source
- Analyzes localization folders
CRXaminer
https://crxaminer.tech/
Risk assessment based on permissions and other factors
Common Attack Patterns
Universal Code Execution
- Extension has wildcard content script match
- Content script forwards postMessage to background
- Background forwards to native messaging
- Native app executes unsanitized input
Impact: RCE on user's machine
Extension Takeover
- Find extension with vulnerable externally_connectable URL
- Compromise the URL (XSS, takeover)
- Send malicious messages directly to background script
- Bypass all content script protections
Forced Extension Load (Windows)
Edit per-user Preferences and forge HMACs to load arbitrary unpacked extensions without prompts. See forced-extension-load-preferences-mac-forgery-windows.md for details.
References
Quick Commands
Query vulnerable extensions from dataset
node query.js -f "metadata.user_count > 250000" "manifest.content_scripts?.length > 0 && manifest.permissions?.includes('nativeMessaging')"
Download and extract extension
ext_id="YOUR_ID"
curl -L -o "$ext_id.crx" "https://clients2.google.com/service/update2/crx?response=redirect&os=mac&arch=x86-64&prod=chromecrx&prodchannel=stable&x=id%3D$ext_id%26uc"
mv "$ext_id.crx" "$ext_id.zip"
unzip -d "$ext_id" "$ext_id.zip"
Load in Chrome for testing
- Go to
chrome://extensions/
- Enable Developer Mode
- Click "Load unpacked"
- Select extracted extension folder