Claude Skills Guide

Manifest V3 vs V2 Security: What Developers Need to Know

Google’s transition from Manifest V2 to Manifest V3 represents the most significant security overhaul in Chrome extension history. If you maintain browser extensions, understanding these security differences is essential for protecting your users and ensuring compliance with Chrome Web Store policies.

Background: Why the Security Overhaul

Manifest V2 served as the standard for Chrome extensions for over a decade. However, security researchers discovered significant vulnerabilities that demanded structural changes. The transition to Manifest V3 wasn’t merely cosmetic—it addressed fundamental architectural weaknesses in how extensions could access and manipulate user data.

Key Security Differences

1. Remote Code Execution

Manifest V2 allowed extensions to execute remote code by loading and running scripts from external URLs:

{
  "manifest_version": 2,
  "name": "Insecure Extension",
  "version": "1.0",
  "permissions": ["<all_urls>"],
  "content_scripts": [{
    "matches": ["<all_urls>"],
    "js": ["https://malicious-server.com/script.js"]
  }]
}

Manifest V3 eliminates this attack vector by requiring all code to be bundled within the extension package:

{
  "manifest_version": 3,
  "name": "Secure Extension",
  "version": "1.0",
  "permissions": ["activeTab"],
  "host_permissions": ["https://example.com/*"],
  "content_scripts": [{
    "matches": ["https://example.com/*"],
    "js": ["content-script.js"]
  }]
}

This change prevents malicious actors from injecting code through compromised CDN domains or man-in-the-middle attacks.

2. Host Permission Granularity

In Manifest V2, requesting broad host permissions like <all_urls> or *://*/* gave extensions unrestricted access to every website a user visited:

// Manifest V2 - Broad access
chrome.webRequest.onBeforeRequest.addListener(
  callback,
  { urls: ["<all_urls>"] }
);

Manifest V3 introduces the host_permissions field and requires explicit, limited access:

{
  "manifest_version": 3,
  "permissions": ["activeTab", "scripting"],
  "host_permissions": [
    "https://specific-site.com/*",
    "https://another-app.com/*"
  ]
}

Users now see permission requests split from installation, making it clearer what data an extension can access.

3. Background Script Restrictions

Manifest V2 allowed persistent background pages that ran continuously:

// Manifest V2 background.js - Always running
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  // Process every single page visit
});

Manifest V3 replaces these with service workers that activate only when needed:

// Manifest V3 background.js - Event-driven
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.action === "processData") {
    // Handle the specific action
  }
});

Service workers terminate when idle, reducing the attack surface and memory footprint.

4. Declarative Net Request取代Web Request

Manifest V2 used the webRequest API for network filtering, which allowed extensions to intercept and modify HTTP requests in real-time:

// Manifest V2
chrome.webRequest.onBeforeRequest.addListener(
  (details) => {
    if (details.url.includes("track")) {
      return { cancel: true };
    }
  },
  { urls: ["<all_urls>"] }
);

Manifest V3 requires declarative rulesets:

{
  "manifest_version": 3,
  "permissions": ["declarativeNetRequest"],
  "host_permissions": ["<all_urls>"],
  "declarative_net_request": {
    "rule_resources": [{
      "id": "block_trackers",
      "enabled": true,
      "path": "rules.json"
    }]
  }
}
// rules.json
[
  {
    "id": 1,
    "priority": 1,
    "action": { "type": "block" },
    "condition": {
      "urlFilter": "tracking",
      "resourceTypes": ["script", "image"]
    }
  }
]

This approach prevents extensions from reading actual request contents, limiting data exposure.

Manifest V3 restricts cookie access to specific domains through the cookieHostOnly flag:

// Manifest V3 - Limited cookie access
chrome.cookies.get({
  url: "https://specific-domain.com",
  name: "session_token"
}, (cookie) => {
  // Can only access cookies for explicitly declared host_permissions
});

This prevents extensions from accessing authentication tokens or session data on unrelated domains.

Migration Strategies

When moving from V2 to V3, consider these practical steps:

  1. Audit all external script sources — Bundle remote scripts or migrate to inline code
  2. Review permission requests — Request only what’s necessary for core functionality
  3. Rewrite network filters — Convert webRequest handlers to declarative rules
  4. Test service worker lifecycle — Ensure background logic handles idle/active transitions
  5. Update content script injection — Use chrome.scripting.executeScript instead of file references

Performance and Security Trade-offs

The Manifest V3 security model introduces some challenges that developers should understand. Service workers may have cold start delays when they’re invoked after being idle—this means background operations can take a few hundred milliseconds to initialize. The declarative net request API is less flexible than the old webRequest API for complex filtering rules, as you cannot inspect or modify request bodies in real-time. Developers building ad blockers or content filters will need to redesign their rule matching logic to work within these constraints.

However, these trade-offs significantly improve user security by reducing the potential impact of extension vulnerabilities. The service worker lifecycle ensures that background code cannot run indefinitely, limiting exposure if an extension is compromised. The declarative approach also means malicious extensions cannot easily exfiltrate user data through intercepted network requests.

Additional Security Improvements

Beyond the major changes, Manifest V3 includes several smaller security enhancements. Cross-origin requests from content scripts are blocked by default. The eval() function and similar dynamic code execution methods are restricted in background contexts. Extension storage is now isolated with automatic encryption for sensitive data.

These cumulative changes create a defense-in-depth strategy that protects users even when individual extension permissions are granted.

Conclusion

Manifest V3’s security model shifts the burden from runtime trust to build-time verification. By requiring bundled code, explicit permissions, and event-driven architecture, Google created a more defensive extension platform. Users benefit from reduced attack surface, while developers gain a clearer permission model and improved extension performance.

For developers, the migration requires upfront investment but delivers lasting security improvements. The Chrome Web Store no longer accepts new Manifest V2 extensions, making the transition mandatory for any active extension project.

Built by theluckystrike — More at zovo.one