# 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".

- Skill: `abelrguezr/browser-extension-pentest` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/browser-extension-pentest`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/browser-extension-pentest/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: abelrguezr (https://skillmd.com/u/abelrguezr)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/abelrguezr/browser-extension-pentest

---


# Browser Extension Pentesting Methodology

A comprehensive guide for security testing browser extensions across Chrome, Firefox, and Chromium-based browsers.

## Quick Start

1. **Get the extension source** (see [Getting Source Code](#getting-source-code))
2. **Analyze manifest.json** for permissions and attack surface
3. **Review content scripts** for DOM-based vulnerabilities
4. **Check background scripts** for message handling issues
5. **Test native messaging** if present
6. **Run the security checklist**

## Getting Source Code

### From Chrome Web Store (by Extension ID)

```bash
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

```json
{
  "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

```json
"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

```json
"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

```json
"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

```json
"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):

```javascript
// 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**:
- `event.isTrusted` - Verify user action triggered it
- `event.origin` - Validate sender domain
- `event.source !== window` - Check same window

### Content Script ↔ Background Script

```javascript
// 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:

```javascript
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  // Async operation
  setTimeout(() => {
    sendResponse({ result: "done" })
  }, 1000)
  return true // Keep channel open
})
```

### Native Messaging

```javascript
chrome.runtime.sendNativeMessage(
  "com.my_company.my_application",
  { text: "Hello" },
  (response) => console.log(response)
)
```

**Native host JSON** (installed on system):

```json
{
  "name": "com.my_company.my_application",
  "path": "/path/to/binary",
  "type": "stdio",
  "allowed_origins": ["chrome-extension://<extension-id>/"]
}
```

**Critical vulnerability pattern**:
1. Content script has wildcard URL match
2. Content script forwards `postMessage` to background via `sendMessage`
3. Background forwards to native app via `sendNativeMessage`
4. 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:

```javascript
// 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 `event.isTrusted` check

### ClickJacking

For `web_accessible_resources` pages:
1. Check CSP for `frame-ancestors` directive
2. Try loading in iframe: `<iframe src="chrome-extension://<id>/page.html"></iframe>`
3. 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-inline`/`unsafe-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
https://crxaminer.tech/

Risk assessment based on permissions and other factors

## Common Attack Patterns

### Universal Code Execution

1. Extension has wildcard content script match
2. Content script forwards postMessage to background
3. Background forwards to native messaging
4. Native app executes unsanitized input

**Impact**: RCE on user's machine

### Extension Takeover

1. Find extension with vulnerable externally_connectable URL
2. Compromise the URL (XSS, takeover)
3. Send malicious messages directly to background script
4. 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](https://www.cobalt.io/blog/introduction-to-chrome-browser-extension-security-testing)
- [Palant - Anatomy of a Basic Extension](https://palant.info/2022/08/10/anatomy-of-a-basic-extension/)
- [Palant - Attack Surface of Extension Pages](https://palant.info/2022/08/24/attack-surface-of-extension-pages/)
- [Spaceraccoon - Universal Code Execution](https://spaceraccoon.dev/universal-code-execution-browser-extensions/)
- [Chrome Extension Manifests Dataset](https://github.com/palant/chrome-extension-manifests-dataset)

## Quick Commands

### Query vulnerable extensions from dataset

```bash
# 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

```bash
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

1. Go to `chrome://extensions/`
2. Enable Developer Mode
3. Click "Load unpacked"
4. Select extracted extension folder

