Is Ad Blocker Pro - stop invasive ads safe?
Ad Blocker Pro is high risk. The extension polls a server every 24 hours and on install; a 'rules' key in the response replaces its ruleset with no version check, signature, or consent. A capture showed rules redirecting 4,600+ domains and blocking 1,485 more.…
Who publishes itAdBlock Inc. - no other listings under this identity
AdBlock Inc. - no other listings under this identity
What this publisher told the store about itself, and the other listings that told it the same thing.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Remote server replaces all blocking rules on every visited site
The extension polls a server every 24 hours and on install; a 'rules' key in the response replaces its ruleset with no version check, signature, or consent.
A capture showed rules redirecting 4,600+ domains and blocking 1,485 more.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-829
- Source
- Dynamic sandbox
The extension's daily alarm fires (or install/update triggers an immediate sync).
syncConfiguration() posts extension ID, version, and storage state to ad-blocker-pro.org/adbpro-202602.php.
If the server response JSON contains a 'rules' key, all existing declarativeNetRequest dynamic rules are removed and replaced with the server-supplied ruleset.
updateNetworkFirewall() is called with unvalidated server data and applies rules across every tab via <all_urls>.
HTTP 200, ~167 KB JSON. Response contained a 'rules' key with 2 declarativeNetRequest rules: Rule 300 (priority 1, redirect action, regexFilter='^http.+', 4,612 requestDomains targeting extension's close.html) and Rule 301 (priority 1, block action, 1,485 requestDomains including google-analytics.com). Captured live during dynamic analysis on 2026-04-25.
- Content-Type
- application/x-www-form-urlencoded
syncuid=&ads_blocked=42&extid=ifidkgmkpihooaknfaapgkejcgcbniek&version=20260206012&c=updateRule replacement logic, sw.js lines 239-293
// sw.js lines 239-245if (json.rules) { let safeRules = json.rules; if (typeof safeRules === 'string') { try { safeRules = JSON.parse(safeRules); } catch (e) { safeRules = []; } } const currentAllowlist = json.allowlist || (await chrome.storage.sync.get('allowlist')).allowlist; await updateNetworkFirewall(safeRules, currentAllowlist);}// sw.js lines 271-295async function updateNetworkFirewall(blockingRules, allowlist = []) { try { const currentRules = await chrome.declarativeNetRequest.getDynamicRules(); const removeRuleIds = currentRules.map(r => r.id); const allowRules = (allowlist || []).map((host, index) => ({ id: 5000 + index, priority: 999, action: { type: "allow" }, condition: { urlFilter: `||${host}`, resourceTypes: ["main_frame", "sub_frame", "script", "image", "xmlhttprequest"] } })); const finalRules = [...(blockingRules || []), ...allowRules]; await chrome.declarativeNetRequest.updateDynamicRules({ removeRuleIds: removeRuleIds, addRules: finalRules }); } catch (e) { console.error("Firewall update failed:", e); }}- ad-blocker-pro.org
Receives telemetry (ID, version, ad-block count, sync storage) and returns the ruleset to enforce. Operator-controlled; no public ownership disclosure.
Every 1 day
Service worker syncs with the remote server every 24 hours via a chrome.alarms periodic alarm, and immediately on install and on extension update.
Fetches the current declarativeNetRequest dynamic rules installed by the extension and prints them to the console. Run in the browser's extension service worker DevTools console to see what ruleset the server has pushed.
- Chrome browser with the extension installed
- Developer mode enabled in chrome://extensions
// Run in the extension's service worker DevTools console (chrome://extensions → inspect views: service worker)// Lists all currently active dynamic declarativeNetRequest rules set by the extension.(async () => { const rules = await chrome.declarativeNetRequest.getDynamicRules(); console.log(`Total dynamic rules: ${rules.length}`); rules.forEach((r, i) => { console.log(`\nRule ${i+1} (id=${r.id}, priority=${r.priority})`); console.log(' action:', JSON.stringify(r.action)); if (r.condition.requestDomains) { console.log(` requestDomains: [${r.condition.requestDomains.length} entries] — first 5:`, r.condition.requestDomains.slice(0,5)); } if (r.condition.regexFilter) { console.log(' regexFilter:', r.condition.regexFilter); } if (r.condition.urlFilter) { console.log(' urlFilter:', r.condition.urlFilter); } });})();- 1Open chrome://extensions, enable Developer mode.
- 2Click 'inspect views: service worker'.
- 3Paste this script into the Console, press Enter.
- 4Compare printed rules against bundled rules.json for server-pushed changes.
Browser storage and usage data sent to ad-blocker-pro.org on every sync
Installing, updating, or leaving Ad Blocker Pro running a day sends your sync storage, sites with ad-blocking disabled, plus ad-block count, ID, version, to ad-blocker-pro.org.
A tracking token from first sync is resent each later request.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Dynamic sandbox
You install Ad Blocker Pro, update it to a new version, or simply leave it running for a day.
A background alarm re-runs the same sync routine every 24 hours whether or not you've touched the extension.
The extension reads your entire browser sync storage and blocked-ad counter, then sends them to ad-blocker-pro.org along with your extension ID and installed version.
The server responds with a persistent tracking token that the extension stores and resends on every future sync.
- Ad-block sync IDsfVA0RasI4eShnIXpjtd2LeSO5OSfgs+bSuRHFZHECW1C58CZYC/8ryBPpTkO8ad0KVjAAGgQ+hIAQ==
A tracking token the server issues on first connection and the extension stores locally, so every later request carries the same identifier.
- Sites you've allowed ads ondocs.google.com, drive.google.com, gemini.google.com, chatgpt.com, slack.com, office.com, microsoft365.com, youtube.com, netflix.com, github.com, stackoverflow.com
Every domain in your personal ad-block exception list is sent in full, showing which sites you added an exception for.
- Ads blocked count5
Your cumulative ad-block counter, which tracks how actively you use the extension.
- Extension identifier and versionojphgkmddbkcgbfdndpabcnfcgmfppdk, version 2026020612
Chrome's unique ID for this specific install, plus the installed extension version.
HTTP 200. Captured in full during dynamic analysis (407-byte body).
- Content-Type
- application/x-www-form-urlencoded
allowlist=docs.google.com,drive.google.com,gemini.google.com,chatgpt.com,slack.com,office.com,microsoft365.com,youtube.com,netflix.com,github.com,stackoverflow.com&lastUpdated=1786890239006&syncnext=43200000&syncuid=sfVA0RasI4eShnIXpjtd2LeSO5OSfgs+bSuRHFZHECW1C58CZYC/8ryBPpTkO8ad0KVjAAGgQ+hIAQ==&ads_blocked=5&extid=ojphgkmddbkcgbfdndpabcnfcgmfppdk&version=2026020612&c=updatesyncConfiguration() and its triggers, sw.js
syncConfiguration() — reads storage, builds the POST, applies the response
sw.jsasync function syncConfiguration(isInstall = false) { console.group("🔄 [AdBlock Sync] Request Initiated"); const now = Date.now(); if (now - lastApiCallTime < 10000) { console.warn("⏳ Sync skipped: Concurrency limit (10s cooldown)."); console.groupEnd(); return; } if (!isInstall) { console.log("⏳ Waiting 5 seconds before API call..."); await new Promise(resolve => setTimeout(resolve, 5000)); if (Date.now() - lastApiCallTime < 10000) return; } lastApiCallTime = Date.now(); try { const [syncData, localData] = await Promise.all([ chrome.storage.sync.get(), chrome.storage.local.get('adsBlocked') ]); const adsBlockedCount = localData.adsBlocked || 0; const postData = new URLSearchParams({ ...syncData, ads_blocked: adsBlockedCount, extid: chrome.runtime.id, version: chrome.runtime.getManifest().version.replaceAll('.', ''), c: 'update' }); console.log("📡 API URL:", CONFIG.apiUrl); console.log("📤 POST Payload:", postData.toString()); const response = await fetch(CONFIG.apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: postData }); if (!response.ok) { console.error("❌ API HTTP Error:", response.status); console.groupEnd(); return; } const rawText = await response.text(); let json; try { json = JSON.parse(rawText); console.log("📦 API Response JSON:", json); } catch (parseError) { console.error("❌ CRITICAL: Valid JSON not found."); console.log(rawText); console.groupEnd(); return; } const newLocalData = {}; const syncUpdate = {}; if (json.rules) { let safeRules = json.rules; if (typeof safeRules === 'string') { try { safeRules = JSON.parse(safeRules); } catch (e) { safeRules = []; } } const currentAllowlist = json.allowlist || (await chrome.storage.sync.get('allowlist')).allowlist; await updateNetworkFirewall(safeRules, currentAllowlist); } for (const [key, value] of Object.entries(json)) { if (key === 'rules') continue; if (key === 'allowlist' || key.startsWith('sync')) { syncUpdate[key] = value; } else { newLocalData[key] = value; } } if (Object.keys(newLocalData).length > 0) await chrome.storage.local.set(newLocalData); if (Object.keys(syncUpdate).length > 0) await chrome.storage.sync.set(syncUpdate); await chrome.storage.sync.set({ lastUpdated: Date.now() }); updateUninstallHook(); console.log("✅ Sync Complete."); } catch (e) { console.error("❌ Sync Exception:", e); } console.groupEnd();}Registered triggers — install, update, and the 24-hour alarm
sw.jschrome.runtime.onInstalled.addListener(async (details) => { chrome.alarms.create(CONFIG.alarmName, { periodInMinutes: 1440 }); if (details.reason === "install") { console.log("🎉 Extension Installed. Loading defaults..."); try { // Load Scripts Locally const scriptsRes = await fetch(chrome.runtime.getURL('initial_scripts.json')); const scriptsData = await scriptsRes.json(); const { allowlist, ...scriptBody } = scriptsData; await chrome.storage.local.set(scriptBody); await chrome.storage.sync.set({ allowlist }); // Load Rules Locally const rulesRes = await fetch(chrome.runtime.getURL('rules.json')); const rulesData = await rulesRes.json(); await updateNetworkFirewall(rulesData, allowlist); // Immediate Sync on Install syncConfiguration(true); updateUninstallHook(); } catch (e) { console.error("Initial setup failed", e); } } else if (details.reason === "update") { console.log("🚀 Extension Updated. Force Sync..."); // API Sync ONLY (Skip local defaults) syncConfiguration(false); }});- ad-blocker-pro.org
Receives your full sync storage, ad-block count, extension ID, and version on every install, update, and daily sync. Operator-controlled; no public ownership disclosure.
Every 1 day
Runs immediately on install, again on every extension update, and then automatically every 24 hours via a background alarm for as long as the extension stays installed.
What it can do
Permissions this extension asks for, as declared in version 2026.02.06.12. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to. The current listed version is 2026.9.14.12, which we have not unpacked yet.
Read and change your data on every site you visit
<all_urls>
Store data in your browser
storage
Run its own code inside the pages you visit
scripting
Block and redirect the requests your browser makes
declarativeNetRequest
Schedule its own background tasks
alarms