Is Ad Blocker safe?
Blocks unwanted ads to provide a cleaner, faster browsing experience.
This extension removes intrusive advertisements such as banners from websites. It uses regularly updated filter lists and provides simple controls with minimal setup.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Ad-blocker.co can remotely replace this extension's network-blocking rules
Every hour, this extension fetches a ruleset from ad-blocker.co, giving it full control over blocked/allowed sites.
The operator can push changes, incl. allowing blocked ad networks or blocking legitimate sites, without an update.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-829
- Source
- Dynamic sandbox
The extension's hourly alarm fires in the background.
No user interaction is required; this happens without user notification 60 minutes after install, then every hour thereafter.
The remote server replaces every dynamic network-blocking rule the extension is using.
The server decides which URLs the extension will block or allow from that point forward, until the next hourly poll.
Every 1 hour
Chrome alarm 'updateNetRulesAlarm' created with periodInMinutes:60 and delayInMinutes:60. Triggers the two-stage fetch-and-inject cycle every hour.
JSON: { "GgZtxR": "/directives/filters/list/", "ZapY": 42 }; the server returns the path of the second fetch, which delivers YHbzkld (the rule array).
Two-stage remote rule injection in net_ff.js
// Stage 1: index fetch resolves to a server-chosen pathasync function fetchAndApplyRuleset(entry) { const indexUrl = "https://ad-blocker.co" + entry.GgZtxR; // e.g. /directives/filters/list/ const cacheKey = `net_item_ZapY_${indexUrl}`; const cached = await chrome.storage.local.get([cacheKey]); if (cached[cacheKey] !== undefined && cached[cacheKey] >= entry.ZapY) { return; // already up-to-date } // Stage 2: fetch the actual ruleset JSON from the server-chosen path const rulesetUrl = await buildTelemetryUrl(indexUrl); const response = await fetch(rulesetUrl); const data = await response.json(); // Remove ALL current dynamic rules and replace with server-provided array const serverRules = data.YHbzkld; // array of declarativeNetRequest rule objects const currentRuleIds = (await chrome.declarativeNetRequest.getDynamicRules()).map(r => r.id); await chrome.declarativeNetRequest.updateDynamicRules({ removeRuleIds: currentRuleIds, // wipe every existing dynamic rule addRules: serverRules // install whatever the server sent }); // Cache the version to avoid redundant refetches data[cacheKey] = entry.ZapY; await chrome.storage.local.set(data);}- ad-blocker.co
Operator server for the two-stage ruleset update: returns the ruleset URL in stage 1, serves the declarativeNetRequest array (YHbzkld) in stage 2. Developer controls this domain.
Google search visits counted and sent to ad-blocker.co on every filter update
Visiting google.com/search increments a counter.
That count, plus how often the extension has blocked something, is sent hourly to the operator with a routine filter-update, revealing how often you use Google Search versus other sites.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Dynamic sandbox
You navigate to any Google Search results page.
The content script runs at document_start on every page load (*://*/*) and checks if the current URL matches google.*/search.
The extension records the visit and reports the running total to ad-blocker.co on the next hourly update.
The sCounter stored in chrome.storage.local is incremented immediately, then transmitted as &scounter=N in every subsequent filter-update request.
Search-detection IIFE in ad_no_main.js (content script, world=ISOLATED)
(async () => { // Runs on every page load (matches: *://*/*) const isGoogleSearch = (location.hostname.startsWith('google.') || location.hostname.startsWith('www.google.')) && location.pathname === '/search'; if (isGoogleSearch) { // Increment the Google-search visit counter in the service worker chrome.runtime.sendMessage({ count: 1, message: 'sCounterMsg' }); }})();URL builder $() in net_ff.js appends scounter to every filter-update request
// Called before every fetch to ad-blocker.coasync function buildTelemetryUrl(baseUrl) { const cohortId = await getCohortId(); // Hcrvj — per-install persistent ID const { bCounter, sCounter, MCP } = await chrome.storage.local.get({ MCP: 0, sCounter: 0, // cumulative Google Search visits bCounter: 0 // cumulative blocked-resource events }); const hoursSinceInstall = MCP ? parseInt(Date.now() - MCP / 3.6e6) : 0; baseUrl += (baseUrl.includes('?') ? '&' : '?') + 'Hcrvj=' + cohortId; baseUrl += '&crx=' + chrome.runtime.id; baseUrl += '&bcounter=' + bCounter; baseUrl += '&scounter=' + sCounter; // Google Search visit count transmitted here baseUrl += '&ucounter=' + hoursSinceInstall; return baseUrl;}JSON filter-index response (200 OK). The scounter=1 value reflects one Google Search visit recorded in the dynamic analysis session.
- Per-install cohort IDHcrvj=ai9WZkg2SXJUU20veDY0
A permanent identifier assigned by the server on first install. Ties every request from your browser to the same identity across sessions.
- Google Search visit countscounter=14
Cumulative number of Google Search pages loaded since the extension was installed. Lets the server measure how often you use Google Search.
- Blocked-resource countbcounter=382
Number of network requests the extension has blocked across all browsing. Approximates your overall browsing volume.
- Extension runtime IDcrx=enpannaocdooaplolobjfclkjefbeocn
Chrome's internal ID for this extension instance. Combined with the cohort ID, this further narrows attribution.
- ad-blocker.co
Operator-controlled server. Receives the Google Search visit count (scounter) and block count (bcounter) with the permanent per-install cohort ID on every hourly filter update.
Permanent per-install tracking ID fetched from ad-blocker.co on first run
The first run, this extension contacts ad-blocker.co for a unique identifier (Hcrvj), stored permanently.
Every later request, including hourly filter updates, carries this ID, letting the operator track your usage across sessions.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-200
- Source
- Dynamic sandbox
You install the extension.
No browsing is needed; the service worker runs L() immediately on the chrome.runtime.onInstalled event.
The extension fetches a permanent tracking ID from ad-blocker.co and links it to every future request your browser makes through this extension.
The Hcrvj value is stored in chrome.storage.local and appended to all outbound requests for the lifetime of the install, with no notification to the user.
Cohort-ID assignment in service_worker.js, function L()
async function getCohortId() { // Read cached ID from persistent storage let { Hcrvj: cohortId } = await chrome.storage.local.get({ Hcrvj: null }); if (!cohortId) { // First run — request a new ID from the server try { const response = await fetch( `https://ad-blocker.co/cid/?crx=${chrome.runtime.id}` ); const data = await response.json(); cohortId = data.Hcrvj || 'default'; } catch { cohortId = 'default'; } // Persist — survives browser restarts and extension updates await chrome.storage.local.set({ Hcrvj: cohortId }); } return cohortId;}JSON: { "Hcrvj": "ai9WZkg2SXJUU20veDY0..." }, the server-assigned cohort ID returned on first install.
The server-assigned cohort ID stored on first install. Persists indefinitely, prepended to every outbound request to ad-blocker.co.
- Location
- chrome.storage.local key 'Hcrvj'
{ "Hcrvj": "ai9WZkg2SXJUU20veDY0AQIDBA"}- ad-blocker.co
Issues the Hcrvj cohort ID on first install via /cid/. Gets the same ID back as a query parameter on every later filter-update and ruleset request, enabling tracking.
What it can do
Permissions this extension asks for, as declared in version 2.0.1. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Read and change your data on every site you visit
<all_urls>
Schedule its own background tasks
alarms
Store data in your browser
storage
Store an unlimited amount of data in your browser
unlimitedStorage
Block and redirect the requests your browser makes
declarativeNetRequest
Run its own code inside the pages you visit
scripting
Watch every request your browser makes
webRequest