Browser extensions occupy a privileged position in the browser security model that most developers underestimate. A Chrome extension with access to tabs and scripting permissions can read the content of any page the user visits, inject arbitrary JavaScript into that page, intercept network requests, and exfiltrate data — all with the user’s explicit (if poorly understood) consent at install time.
Two unpatched vulnerabilities in a major AI browser assistant were disclosed in mid-2026, demonstrating that extensions can be weaponised by other extensions through event injection and URL parameter abuse. The pattern is not new, but the AI integration context has expanded the blast radius significantly. If your organisation develops browser extensions, or depends on them, the security model is worth understanding in depth.
The Manifest V3 Security Model
Chrome’s Manifest V3 (MV3) was a significant architectural change from MV2, motivated in part by security and performance. Key changes relevant to security:
- Service workers instead of persistent background pages: Extensions no longer maintain a persistent background process. Service workers are event-driven and terminate when idle.
- Declarative network rules instead of webRequest blocking: Dynamic network request interception is now handled through
declarativeNetRequest, which pre-declares rules rather than executing arbitrary code on network events. - Restricted remote code execution: Extensions can no longer execute remotely fetched code. The
eval()and remote script injection patterns that were common in MV2 are blocked.
MV3 raises the bar, but it does not eliminate the attack surface. Content scripts still run in the context of web pages and can read DOM content. Extensions with broad host permissions still have significant data access.
Vulnerability Class 1: Content Script XSS
Content scripts are injected into web pages and run in a “isolated world” — they share the DOM with the page’s JavaScript but have a separate JavaScript context. The isolation is not complete. Content scripts that write unsanitised data to the DOM, or that use innerHTML with user-controlled or page-controlled content, are vulnerable to XSS with extension privileges.
// Vulnerable: writing page content back to DOM without sanitisation
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status === 'complete') {
chrome.scripting.executeScript({
target: { tabId },
func: () => {
const title = document.title; // Attacker controls this
document.getElementById('ext-overlay').innerHTML =
`<div>Page: ${title}</div>`; // Reflected XSS in extension context
}
});
}
});
// Safe: use textContent for plain text, or DOMPurify for HTML
document.getElementById('ext-overlay').textContent = `Page: ${title}`;
// Or if HTML is required:
import DOMPurify from 'dompurify';
document.getElementById('ext-overlay').innerHTML = DOMPurify.sanitize(content);
XSS in a content script is more dangerous than page-level XSS because the script may have access to extension APIs including chrome.storage (which may contain credentials or tokens) and chrome.tabs (which can interact with other tabs).
Vulnerability Class 2: Message Passing Injection
Extensions communicate between components (content scripts, service workers, popup pages) using chrome.runtime.sendMessage and chrome.runtime.onMessage. If a message listener does not validate the sender and does not sanitise message contents, a malicious page can send crafted messages to the extension’s service worker.
// Vulnerable: no sender validation
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === 'executeScript') {
// Arbitrary code path triggered by page message
chrome.scripting.executeScript({
target: { tabId: sender.tab.id },
code: message.scriptCode // Never eval arbitrary code from messages
});
}
});
// Safe: validate sender origin and action before acting
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
// Only accept messages from content scripts in trusted contexts
if (!sender.tab || sender.tab.url.startsWith('chrome-extension://')) {
return false; // Reject messages not from expected sources
}
// Use a strict allowlist of valid actions
const allowedActions = ['updateBadge', 'fetchData', 'openPopup'];
if (!allowedActions.includes(message.action)) {
return false;
}
// Handle specific actions with fixed logic, no dynamic execution
handleAction(message.action, message.payload);
});
The 2026 AI assistant disclosure specifically involved a missing event.isTrusted check — synthetic click events dispatched by malicious scripts were being treated as genuine user interactions, triggering privileged extension behaviour.
Vulnerability Class 3: Over-Permissioned Manifest
Extension manifests that request broad permissions create unnecessary attack surface. The principle of least privilege applies directly: an extension only needs the permissions it actually uses.
// Overly broad — common in real-world extensions
{
"manifest_version": 3,
"permissions": ["tabs", "cookies", "storage", "webRequest", "history"],
"host_permissions": ["<all_urls>"]
}
// Scoped to actual requirements
{
"manifest_version": 3,
"permissions": ["storage"],
"host_permissions": [
"https://api.yourservice.com/*",
"https://app.yourservice.com/*"
]
}
<all_urls> host permission means the extension can inject content scripts into any page the user visits. This is rarely justified. Scope host permissions to the specific domains the extension needs to interact with.
Vulnerability Class 4: Insecure Storage of Sensitive Data
Extensions use chrome.storage.local and chrome.storage.sync for persistent data. These APIs do not encrypt stored data — contents are accessible to any code running in the extension’s context, and on disk at the path Chrome uses for extension storage.
Sensitive data (access tokens, API keys, user credentials) should not be stored in extension storage without encryption. For OAuth tokens: use the token immediately and refresh on demand rather than storing long-lived tokens persistently. If storage is required, encrypt with a key derived from a user-provided secret or from the browser’s built-in credential storage where available.
Reviewing Third-Party Extensions
When your organisation depends on third-party extensions (password managers, AI assistants, developer tools), the security review questions are:
What permissions does it request? Enumerate all requested permissions and host permissions. Any <all_urls> permission means the extension has access to every page.
Does it load remote code? Extensions should not load scripts from external URLs. Check content_security_policy in the manifest. A relaxed CSP (script-src 'unsafe-eval') or the absence of a CSP is a red flag.
What does it do with page content? Read the source code if it’s open source, or review the extension’s documented data collection practices. Extensions with access to all URLs and network request capabilities can exfiltrate significant amounts of browsing data.
Has it been audited? For extensions used in sensitive environments, look for published security audits or academic analysis. High-profile extensions used across large enterprise populations are occasionally audited by security researchers — check if yours has been.
The Chrome Web Store’s permission request is the primary (and often only) security gate users encounter before installation. It is not sufficient on its own for enterprise risk management.