Protecting JavaScript in Browser Extensions

← Back to Blog

Why Browser Extensions Need Special Protection

Browser extensions are distributed as ZIP archives containing HTML, CSS, and JavaScript files. Anyone who installs your extension can immediately access all of your source code by navigating to the browser's extensions folder. There is no binary compilation, no server to hide behind — your entire codebase is sitting in plain text on users' machines.

This makes browser extensions one of the most important use cases for JavaScript obfuscation.

The Browser Extension Attack Surface

Here's exactly how easy it is to read an unprotected extension's code:

  • On Chrome: Navigate to chrome://extensions, click "Details," then "Extension package" to find the files on disk
  • Or simply open Chrome's user data directory: the extensions folder contains all installed extensions
  • On Firefox: Extensions are stored as XPI files (ZIP archives) in your profile directory

Without obfuscation, a competitor can read, copy, and fork your extension's code in minutes.

What to Obfuscate in an Extension

Extension packages typically contain:

  • background.js / service-worker.js — Your extension's core logic. Always obfuscate.
  • content-scripts — Code injected into web pages. Always obfuscate.
  • popup.js / options.js — UI logic. Obfuscate if it contains sensitive business logic.
  • manifest.json — Cannot be obfuscated (browser requires it as-is).
  • Third-party libraries — Skip (they're already public).

Build Pipeline for Extensions

Use webpack-obfuscator or a similar build-integrated tool:

// webpack.extension.config.js
const WebpackObfuscator = require('webpack-obfuscator');
const CopyPlugin = require('copy-webpack-plugin');

module.exports = {
  entry: {
    background: './src/background.js',
    content: './src/content.js',
    popup: './src/popup.js'
  },
  output: { path: path.resolve(__dirname, 'dist') },
  plugins: [
    new CopyPlugin({ patterns: [{ from: 'manifest.json', to: '' }] }),
    new WebpackObfuscator({
      stringArray: true,
      rotateStringArray: true,
      compact: true,
      selfDefending: true,
      deadCodeInjection: false  // Keep size reasonable
    }, [])
  ]
};

Chrome Web Store Considerations

The Chrome Web Store allows obfuscated extensions but requires you to submit your unobfuscated source code separately for review. Google's reviewers will analyze the non-obfuscated version. This is a reasonable policy — it ensures extensions are reviewed for safety even when their distributed code is protected.

Be prepared to submit your source code during the review process, and make sure your obfuscated output is genuinely functionally identical to your source.

API Key Protection in Extensions

Extensions often need to communicate with external APIs, and those APIs often require keys. Storing API keys in extension code is risky — even obfuscated, a determined attacker can extract them at runtime. For truly sensitive keys, use a proxy server that holds the key server-side and exposes a simpler authenticated API to your extension.

Protect your extension: Use our free obfuscator on each JS file in your extension. For automated builds, integrate webpack-obfuscator into your extension build pipeline.