Is Clean Adblocker safe?
Clean Adblocker reports every site you visit to its own server and reframes Google/Amazon search pages to scrape and upload the results.
On every page you visit, the extension sends the page URL, the previous URL, and a persistent per-install ID to comet.cleanadblocker.com, gated by a consent check that is always true on Chrome. Separately, when you search on Google it strips the page's anti-framing headers and loads a hidden copy of the search results to extract the query and result titles/URLs/prices, and it reads the same kind of data directly off Amazon search pages, uploading both to the same vendor backend.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Clean Adblocker reports every site you visit, tagged with a permanent ID
Code analysis shows Clean Adblocker sends the URL and referrer of every site you visit to its own server, tagged with a UUID that persists across sessions.
The setting meant to disable this defaults to on for every Chrome install.
You visit any ordinary website, for example a news article or a shopping page.
This is not limited to pages with ads, popups or cookie banners to block.
The extension records that page's address and the page you came from, tags them with a permanent per-install ID, and queues them for upload to its own server.
The upload happens automatically, with no visible prompt or indicator on the page.
consent-gate.js: the switch meant to gate this collection
"use strict";
class ConsentGate {
container = new DataContainer('dataProcessingConsent', {
hasConsent: "chrome" !== 'firefox'
});
async getConsent() {
const data = await this.container.get();
return data.hasConsent;
}
async setConsent(hasConsent) {
await this.container.set({
hasConsent
});
}
}
const dataProcessingConsent = new ConsentGate();page-data-store.js and tab.js: which pages get reported, and how
async create(url) {
const isValidSite = url.startsWith('http');
const host = getUrlHost(url);
const settings = await userData.getSettings();
const shouldWorkOnThisSite = isValidSite && settings.enabled;
let enabled = shouldWorkOnThisSite;
let hideCookieBanners = shouldWorkOnThisSite && !!settings.hideCookieBanners;
let blockPopups = shouldWorkOnThisSite && settings.blockPopups;
let showBlockedPopupNotification = blockPopups;
if (shouldWorkOnThisSite) {
const [isHostDeactivated, isPopupsAllowed, isPopupShowNotification, isCookieBannersAllowed] = await Promise.all([deactivatedSites.isHostDeactivated(host), popupAllowedSites.isAllowed(host), popupShowNotificationList.getValueByHost(host), cookieBannersAllowedSites.isAllowed(host)]);
enabled = enabled && !isHostDeactivated;
blockPopups = blockPopups && !isPopupsAllowed;
showBlockedPopupNotification = blockPopups && isPopupShowNotification !== false;
hideCookieBanners = hideCookieBanners && !isCookieBannersAllowed;
}
return {
pageUrl: url,
hostAddress: host,
enabled,
hideCookieBanners,
blockPopups,
showBlockedPopupNotification,
isValidSite,
blockTracking: settings.blockTracking,
previousUrl: '',
clickId: crypto.randomUUID(),
stats: {
total: 0,
ads: 0,
trackers: 0,
popups: 0,
cookieBanners: 0,
timeSaved: 0
}
};
}const [pageData, tabData] = await Promise.all([pageDataStore.create(url), this.container.get()]);
tabData.lastCapturedSerpUrlByTab ??= {};
pageData.previousUrl = existingPageData?.pageUrl || tabData.tabOpenInitiators[tabId]?.url || '';
setTimeout(async () => {
if (pageData.isValidSite) {
await diagnosticsReporter.addReportsBulk([{
loadTime: new Date().getTime(),
previousUrl: pageData.previousUrl,
pageUrl: pageData.pageUrl,
clickId: pageData.clickId || undefined,
trt: tabData.transitions[tabId]?.[url]?.trt,
trq: tabData.transitions[tabId]?.[url]?.trq
}]);
}
await this.clearData(tabId, url);
}, 100);
await pageDataStore.setData(tabId, pageData);
await this.onActivated();| Field | Value | Why it matters | |
|---|---|---|---|
Permanent device ID | a1b2c3d4-5e6f-47a8-9b1c-2d3e4f5a6b7c | A random ID created on first install and reused on every report, letting the vendor link all your visits together. | |
Page you visited | https://www.nytimes.com/2026/09/12/technology/ai-chips.html | The full address of the page you just loaded. | |
Page you came from | https://www.google.com/search?q=latest+ai+chip+news | The address of the page you were on right before, exposing your browsing path. | |
Country code | US | Your approximate location, derived from your IP address. | |
Navigation type | link | How you arrived at the page: typed, clicked a link, or redirected. |
- comet.cleanadblocker.com
The vendor's own backend for Clean Adblocker. Receives the browsing report described above at /convert.
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.
Clean Adblocker strips Google's anti-framing headers to copy your searches
Code analysis shows Clean Adblocker removes Google's X-Frame-Options and CSP headers to reload your search in an off-screen iframe, then extracts and uploads your query and results.
Amazon product searches are extracted the same way.
You run a search on google.com, or search for a product on amazon.com.
No click on a result is needed; running the search is enough.
The extension reloads the same search page in an off-screen background frame, reads the query and every result shown, and uploads them to its own server.
On Google, it first strips the page's anti-framing headers so the off-screen copy is allowed to load at all.
renderer.js: stripping Google's frame protection, then reloading the page off-screen
createFrameHeaderRule(domain) {
return {
id: DNR_RULE_ID,
priority: 1,
condition: {
requestDomains: [domain],
resourceTypes: ['sub_frame']
},
action: {
type: 'modifyHeaders',
responseHeaders: [{
header: 'X-Frame-Options',
operation: 'remove'
}, {
header: 'Frame-Options',
operation: 'remove'
}, {
header: 'Content-Security-Policy',
operation: 'remove'
}, {
header: 'Content-Security-Policy-Report-Only',
operation: 'remove'
}]
}
};
}async render(url, localeParams = {}, timeoutMs = 25000) {
if (!this.isSupported()) return null;
const domain = new URL(url).hostname;
const localizedUrl = this.applyLocaleParams(url, localeParams);
try {
await this.toggleDNRRule(domain, true);
await this.toggleContentScript(domain, true);
await this.ensureOffscreenDocument();
const result = await chrome.runtime.sendMessage({
target: 'offscreen',
type: 'RENDER_SERP_IN_IFRAME',
data: {
url: localizedUrl,
timeout: timeoutMs
}
});
if (result?.success) {
return {
...result.data,
engine: 'google'
};
}
remoteLogger.logError(new Error(result?.error || 'Unknown extraction error'), 'SerpRenderer.render');
return null;
} catch (error) {
remoteLogger.logError(error, 'SerpRenderer.render');
return null;
} finally {
await this.toggleContentScript(domain, false).catch(() => {});
await this.toggleDNRRule(domain, false).catch(() => {});
}
}| Field | Value | Why it matters | |
|---|---|---|---|
Search query text | best noise cancelling headphones under 200 | The exact words you typed into the search box. | |
Result titles and links | Sony WH-1000XM5, amazon.com/dp/B09XS7JWHH | The title and destination link of every organic and sponsored result shown to you. | |
Amazon product data | $29.99, 4.6 stars, Sponsored | Product titles, prices, ratings and Sponsored or Amazon's Choice labels from your Amazon results. | |
Search session marker | 6f1a2e9d-88c4-4b0a-9e21-3a7c5d2f9b41 | A per-search click ID letting the vendor tie this search to other reports about you. |
- comet.cleanadblocker.com
The vendor's own backend for Clean Adblocker. Receives extracted Google and Amazon search-result data at /update.
Scans an unpacked extension's JS for declarativeNetRequest rules that remove X-Frame-Options or CSP response headers, and prints the target domain.
#!/usr/bin/env node
// check_frame_header_strip.js
// Usage: node check_frame_header_strip.js /path/to/unpacked
const fs = require('fs');
const path = require('path');
const root = process.argv[2];
if (!root) {
console.error('Usage: node check_frame_header_strip.js <path-to-unpacked-extension>');
process.exit(1);
}
const TARGET_HEADERS = ['x-frame-options', 'content-security-policy', 'frame-options'];
const hits = [];
function walk(dir) {
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) {
walk(full);
} else if (entry.isFile() && entry.name.endsWith('.js')) {
const text = fs.readFileSync(full, 'utf8');
if (!/modifyHeaders/.test(text)) continue;
const lower = text.toLowerCase();
const matchedHeader = TARGET_HEADERS.find(h => lower.includes(h));
if (matchedHeader && /operation\s*:\s*['"]remove['"]/.test(text)) {
const domainMatch = text.match(/requestDomains\s*:\s*\[([^\]]+)\]/);
hits.push({ file: full, header: matchedHeader, domains: domainMatch ? domainMatch[1] : '(dynamic)' });
}
}
}
}
walk(root);
if (hits.length === 0) {
console.log('No declarativeNetRequest rules removing framing-protection headers were found.');
process.exit(0);
}
console.log('Found rules that strip framing-protection headers:');
for (const hit of hits) {
console.log(` ${hit.file}\n header: ${hit.header}\n domains: ${hit.domains}`);
}
console.log('\nThis pattern lets the extension load a target site in an iframe it opted out of via these headers.');
- 1Unpack the .crx or unzip the extension.
- 2Run: node check_frame_header_strip.js /path/to/unpacked
- 3Any match means that domain's anti-framing protection can be defeated.
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.
Where it sends data
Destinations our analysis observed Clean Adblocker contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.
- comet.cleanadblocker.com
Clean Adblocker sends data to comet.cleanadblocker.com. No other extension we have analysed sends data here.