Hacktricks-skills browser-extension-pentest
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".
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/browser-extension-pentesting-methodology/browser-extension-pentesting-methodology/SKILL.MDBrowser 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
→ Profile Path →chrome://version/
folderExtensions/ - File archiver: Rename
to.crx
and extract.zip
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:
- Can communicate with native binaries (RCE risk)nativeMessaging
- Can access all tab datatabs
- Can read all cookiescookies
- Can intercept/modify network requestswebRequest
- Can access extension storagestorage
Content Scripts
"content_scripts": [ { "js": ["script.js"], "matches": ["https://example.com/*"], "exclude_matches": ["*://*/*business*"], "run_at": "document_idle" } ]
Key fields:
- URLs where script injects (wider = more attack surface)matches
- When script runs (run_at
,document_start
,document_end
)document_idle
- JavaScript files to injectjs
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
orunsafe-inline
directivesunsafe-eval- Missing
for web_accessible_resourcesframe-ancestors
Communication Patterns
Web Page ↔ Content Script
PostMessage (most common):
// Web page sends window.postMessage({ type: "FROM_PAGE", text: "data" }, "*") // Content script receives window.addEventListener("message", (event) => { if (event.source !== window) return if (event.data.type === "FROM_PAGE") { // Handle message } })
Security checks needed:
- Verify user action triggered itevent.isTrusted
- Validate sender domainevent.origin
- Check same windowevent.source !== window
Content Script ↔ Background Script
// Send message chrome.runtime.sendMessage({ greeting: "hello" }) // Receive message 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) => { // Async operation setTimeout(() => { sendResponse({ result: "done" }) }, 1000) return true // Keep channel open })
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
to background viapostMessagesendMessage - 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:
// Vulnerable: Reading untrusted DOM 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
checkevent.isTrusted
ClickJacking
For
web_accessible_resources pages:
- Check CSP for
directiveframe-ancestors - 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:
- Permissions: Minimize requested permissions
- Host permissions: Limit to necessary domains only
- CSP: Strong policy, no
/unsafe-inlineunsafe-eval - Externally connectable: Set to
if not needed{}- No XSS-vulnerable URLs listed
- Web accessible resources: Minimize or empty
- Check for ClickJacking if present
- PostMessage communication: Validate origin, source, isTrusted
- DOM access: Don't trust DOM data from web page
- Native messaging: Sanitize all input, validate output
- Sensitive data: Not in code, memory, or clipboard
- File system: Sensitive data not stored unprotected
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
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
- Cobalt - Chrome Extension Security Testing
- Palant - Anatomy of a Basic Extension
- Palant - Attack Surface of Extension Pages
- Spaceraccoon - Universal Code Execution
- Chrome Extension Manifests Dataset
Quick Commands
Query vulnerable extensions from dataset
# Extensions with 250k+ users, content_scripts, and nativeMessaging 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