Skip to content

Essential Privacy Extensions

💡
Before you start

Python 3, a terminal, and the zip and unzip commands (already present on macOS and most Linux systems; on Windows, Explorer can open a renamed .zip instead).

Nothing is installed into your browser and no extension store is contacted. The lab builds its own example extension in a scratch folder you can delete afterwards.

You need no prior knowledge of how extensions work. The single idea is that every extension ships a plain-text file listing exactly what it is allowed to do, and the browser enforces that list and nothing beyond it.

Why Privacy Extensions Matter

Even with good browser settings, websites use trackers, fingerprinting, and third-party cookies to follow you across the internet. Privacy extensions add layers of protection that browsers alone cannot provide.

⚠️
Less is more

Installing too many extensions can actually harm your privacy by making your browser fingerprint more unique. Stick to the essentials listed here.

uBlock Origin (Essential)

uBlock Origin is the most effective content blocker available. It blocks ads, trackers, malware domains, and more while using minimal system resources.

Installation

  • Firefox: Search "uBlock Origin" in Firefox Add-ons and click "Add to Firefox"
  • Chrome/Brave: Search "uBlock Origin" in the Chrome Web Store

Recommended Settings

Click the uBlock Origin icon, then the gear icon to open the Dashboard:

  • Under "Filter lists," enable EasyList, EasyPrivacy, and Fanboy's Annoyances
  • Enable the Malware domains list under "Malware protection"
  • Click "Update now" to fetch the latest filter lists
💡
uBlock Origin vs uBlock

Make sure you install uBlock Origin (by Raymond Hill), not "uBlock" which is a different, less trustworthy fork.

Privacy Badger

Developed by the Electronic Frontier Foundation (EFF), Privacy Badger automatically learns to block invisible trackers based on their behavior rather than predefined lists.

  • Install from your browser's extension store (search "Privacy Badger")
  • It works automatically with no configuration needed
  • The icon shows how many trackers were found on each page (red = blocked, yellow = partially blocked, green = allowed)

Privacy Badger complements uBlock Origin by catching trackers that filter lists may miss.

ClearURLs

Many links contain tracking parameters (like ?utm_source= or &fbclid=). ClearURLs automatically strips these tracking elements from URLs before you visit them.

  • Install from your browser's extension store
  • Works silently in the background, no configuration needed
  • Click the icon to see statistics on how many tracking elements were removed

LocalCDN (or Decentraleyes)

Many websites load common libraries (jQuery, Font Awesome, etc.) from centralized CDNs like Google or Cloudflare. These CDN requests can track you across sites. LocalCDN intercepts these requests and serves the libraries locally instead.

  • LocalCDN is the actively maintained fork (recommended)
  • Decentraleyes is the original, still functional but less frequently updated
  • Install one or the other, not both
  • No configuration needed after installation

Extensions to Avoid

Some popular extensions actually harm your privacy:

  • Free VPN extensions: Many log and sell your browsing data
  • Multiple ad blockers: Using more than one causes conflicts and slows browsing
  • "Web of Trust" (WOT): Was caught selling detailed browsing histories
  • Coupon/deal finders: Track every page you visit to find deals
  • Extensions requesting excessive permissions: If a simple tool asks to "read and change all data on all websites," avoid it

Now Do It Yourself: Read What an Extension Is Allowed to Do

The page above recommends four extensions and warns that more is not better. Both are good advice, and neither helps you judge the next extension you are tempted by. That judgement comes down to one file every extension carries, which you can read in fifteen minutes and never have to take on trust again.

You need Python 3 and the zip/unzip commands. Nothing is installed into your browser and no extension store is contacted. Every output below came from running these exact commands.

1
Write down what a modest extension asks for

Go: open a terminal, then mkdir extlab and cd extlab. Nothing here installs anything into your browser.

Do: save this as manifest.json. Every browser extension ships one of these — it is the complete, machine-readable list of what the extension may do:

{
  "manifest_version": 3,
  "name": "Dark Mode for Docs",
  "version": "1.2.0",
  "description": "Adds a dark theme to your document editor.",
  "permissions": ["storage"],
  "host_permissions": ["https://docs.example.com/*"]
}

You should see: a small file. It claims two powers: keep its own settings, and act on one named site.

That is a narrow extension. It cannot see other tabs, cannot read cookies, and cannot touch any site except the one it names. The manifest is not marketing — the browser enforces exactly this list and nothing more.

If not: if a later step reports JSONDecodeError, the file has a stray comma or a smart quote from copy-paste. JSON allows only straight double quotes and no trailing comma before }.

2
Build something that says what each permission means

Go: the same folder.

Do: save this as explain-perms.py. It turns the manifest's shorthand into plain English and judges the overall footprint:

import json, sys, pathlib

MEANING = {
    "storage":        "keep its own settings — harmless",
    "tabs":           "see the title and URL of every tab you have open",
    "webRequest":     "observe every network request the browser makes",
    "webRequestBlocking": "observe AND alter or block every request",
    "cookies":        "read and write cookies, including login sessions",
    "history":        "read your entire browsing history",
    "bookmarks":      "read and change your bookmarks",
    "downloads":      "see and start downloads",
    "clipboardRead":  "read whatever you have copied",
    "nativeMessaging": "talk to a program installed outside the browser",
    "<all_urls>":     "read and change the contents of EVERY site you visit",
}

path = sys.argv[1] if len(sys.argv) > 1 else "manifest.json"
m = json.loads(pathlib.Path(path).read_text(encoding="utf-8"))

print(f"{m.get('name','?')}  v{m.get('version','?')}")
print(f"  {m.get('description','')}\n")

perms = list(m.get("permissions", [])) + list(m.get("host_permissions", []))
if not perms:
    print("  no permissions requested")
worst = 0
for p in perms:
    if p in ("<all_urls>", "*://*/*", "http://*/*", "https://*/*"):
        print(f"  [FULL ACCESS] {p:<28} {MEANING.get('<all_urls>')}")
        worst = 2
    elif p.endswith("/*") and "*" not in p.split("//")[-1].split("/")[0]:
        print(f"  [one site]    {p:<28} read and change that site only")
        worst = max(worst, 0)
    else:
        note = MEANING.get(p, "no plain-English note for this one — look it up")
        level = "[sensitive]  " if p in ("tabs","webRequest","webRequestBlocking","cookies",
                                         "history","clipboardRead","nativeMessaging") else "[minor]      "
        print(f"  {level} {p:<28} {note}")
        worst = max(worst, 1 if level.strip() == "[sensitive]" else 0)

print()
print(["FOOTPRINT: narrow — it can only touch what it names",
       "FOOTPRINT: broad — it can see things beyond its stated job",
       "FOOTPRINT: TOTAL — this extension can read and modify every page you load"][worst])

Run it on the modest manifest:

python3 explain-perms.py

You should see: the two claims spelled out, and a verdict:

Dark Mode for Docs  v1.2.0
  Adds a dark theme to your document editor.

  [minor]       storage                      keep its own settings — harmless
  [one site]    https://docs.example.com/*   read and change that site only

FOOTPRINT: narrow — it can only touch what it names

This is what a well-scoped extension looks like: the permissions match the description. A dark theme for one site needs exactly this and nothing else.

If not: FileNotFoundError means the two files are in different folders — run ls and check that manifest.json and explain-perms.py both appear.

3
Watch the same extension change after an update

Go: the same folder.

Do: save this as greedy.json. Read it carefully first: the name is the same, the description is word for word identical, and only the version moved:

{
  "manifest_version": 3,
  "name": "Dark Mode for Docs",
  "version": "1.3.0",
  "description": "Adds a dark theme to your document editor.",
  "permissions": ["storage", "tabs", "cookies", "webRequest", "history"],
  "host_permissions": ["<all_urls>"]
}

Now run the explainer on it:

python3 explain-perms.py greedy.json

You should see: the same extension, one version later, asking for everything:

Dark Mode for Docs  v1.3.0
  Adds a dark theme to your document editor.

  [minor]       storage                      keep its own settings — harmless
  [sensitive]   tabs                         see the title and URL of every tab you have open
  [sensitive]   cookies                      read and write cookies, including login sessions
  [sensitive]   webRequest                   observe every network request the browser makes
  [sensitive]   history                      read your entire browsing history
  [FULL ACCESS] <all_urls>                   read and change the contents of EVERY site you visit

FOOTPRINT: TOTAL — this extension can read and modify every page you load

🔴 This is the actual attack, and it is not hypothetical. Popular extensions get sold, or their developer account gets compromised, and an update widens the permissions. The listing keeps its old name, its old reviews and its old star rating — the description above did not change a single character. <all_urls> plus cookies means it can read your banking session on any page you open.

If not: if the output looks the same as step 2, you ran it without the filename — the command needs greedy.json on the end, or it defaults to manifest.json.

4
Open a packaged extension without installing it

Go: the same folder.

Do: an extension file is an ordinary ZIP archive with a different ending. Build one, then look inside it:

mkdir -p pkg
cp greedy.json pkg/manifest.json
echo 'console.log("extension code");' > pkg/background.js
cd pkg && zip -q -r ../darkmode-1.3.0.xpi . && cd ..
unzip -l darkmode-1.3.0.xpi

You should see: its contents listed, without the browser ever running it:

  Length      Date    Time    Name
---------  ---------- -----   ----
       31  2026-08-28 06:04   background.js
      257  2026-08-28 06:04   manifest.json
---------                     -------
      288                     2 files

Your dates and the exact byte counts will differ — the archive is built at the moment you run it, so an automated re-check of this page will always report this block as differing.

Firefox uses .xpi and Chrome uses .crx; both are ZIP files. Anything you can download, you can read before you trust it.

If not: zip: command not found — install it (sudo apt install zip) or skip ahead: on Windows, rename the file to .zip and open it in Explorer, which does the same job.

5
Read the manifest straight out of the package

Go: the same folder.

Do: pull just the manifest out of the archive and run it through your explainer — the check you would do on a real download:

unzip -p darkmode-1.3.0.xpi manifest.json > extracted.json
python3 explain-perms.py extracted.json

You should see: the same report as step 3, because it is the same manifest — only now it came out of the packaged file rather than the source folder. Its closing lines (the full report is identical to step 3's):

  [sensitive]   history                      read your entire browsing history
  [FULL ACCESS] <all_urls>                   read and change the contents of EVERY site you visit

FOOTPRINT: TOTAL — this extension can read and modify every page you load

You now have a habit worth keeping. Firefox lists an add-on's permissions on its listing page before you install, and again at about:addons afterwards — and it asks again when an update wants more. That prompt is the one people click through fastest, and step 3 is what it is trying to tell you.

Inspecting a real add-on from the store was not re-run for this page — downloading one needs a network connection this page could not make. The technique is identical: the file is a ZIP either way.

If not: caution: filename not matched means the archive has no manifest.json at its top level — run unzip -l again and use the exact path shown, some packages nest their files one folder deep.

🎉
Check yourself before moving on

An extension you have used for two years pops up a prompt saying it needs new permissions. It has 400,000 users and 4.7 stars. What does the rating tell you about the new permissions? Answer: Nothing at all. Reviews and stars accumulate against the OLD version; step 3 showed name, description and listing staying identical while the permissions went from one site to every site. The only thing that answers the question is the permission list in front of you.

Now do it without the page: open about:addons in Firefox, pick an extension you already have, and read its permissions. Ask whether each one is needed for the job you installed it to do. If any is not, you have found something worth removing — and you did it without a guide.

Summary

A solid privacy extension setup includes:

  • uBlock Origin - Content blocking (ads, trackers, malware)
  • Privacy Badger - Behavioral tracker detection
  • ClearURLs - URL tracking parameter removal
  • LocalCDN - Local CDN resource delivery
🎉
Your browser is now hardened!

These four extensions dramatically reduce tracking while keeping websites functional. If a site breaks, try disabling extensions one by one to find the cause.