Is Web Ad Blocker safe?

High risk

Web Ad Blocker is high risk. Web Ad Blocker's background worker fetches JSON config from webadblocker.org on every start or install, storing it in chrome.storage. We observed nearly 40 values, covering the upgrade footer, trial length, and upsell-exempt domains.…

webadblocker.orgv6.6.9Chrome Web Store
75Risk
Who publishes it

Web Ad Blocker - no other listings under this identity

What this publisher told the store about itself, and the other listings that told it the same thing.

Publisher
webadblocker.org
Declared legal entity
Web Ad Blocker
Registered address
261 N University Dr, Suite 500-53, Plantation, FL 33324, US

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

Publishers can request a review.

Findings

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-829
SourceAI SANDBOX

Remote Server Config Controls Web Ad Blocker's Behavior Without a Code Update

Web Ad Blocker's background worker fetches JSON config from webadblocker.org on every start or install, storing it in chrome.storage.

We observed nearly 40 values, covering the upgrade footer, trial length, and upsell-exempt domains.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You start Chrome or install Web Ad Blocker.

Chrome fires the onStartup and onInstalled events the extension listens for.

The extension did this

The extension fetches a settings file from webadblocker.org and applies it immediately.

The response controls interface and monetization behavior, such as whether an upgrade footer appears, without a new extension release.

02EvidenceFIELD TABLE
A subset of the roughly 40 configuration keys returned in one response
FieldValueWhy it matters
Upgrade footer toggle
SHOW_INLINE_FOOTER_EVENT: yesTurns the in-page upgrade footer overlay on or off for users who haven't paid.
Footer split-test variant
SHOW_FOOTER_STRATEGY_C: yes, SHOW_FOOTER_STRATEGY_D: yesChooses which footer design variant is shown as part of a split test.
Free trial length
TRIAL_DURATION_DAYS: 3Sets how many days the free trial lasts before the extension prompts you to pay.
Post-trial reminder schedule
POST_TRIAL_REMINDER_SKIP_DAYS: 2Controls how many days after the trial ends before payment reminder prompts resume.
License verification endpoint
URL_API_REGISTER: https://keys.webadblocker.org/web-service-registerPoints the extension at the server URL used to register a paid license key.
Domains exempt from upsell prompts
CORPORATE_WHITELIST: ["chase.com", "google.com", "paypal.com", ...]Lists sites, including major banks and Google and Microsoft services, where the extension suppresses its own monetization prompts.
03EvidenceNETWORK CAPTURE
Captured request
GEThttps://webadblocker.org/pluginservice-mv3/ajax-getconfig.php
HTTP 200; JSON body of roughly 4,000 bytes containing about 40 configuration keys (see field table above). The same request was captured 16 times across a single install-and-startup replay.
Headers
CookiePHPSESSID=<redacted>; track_uid=<redacted>; track_installdate=2026-08-16; track_first_visit=thankyou%20chrome%20(ch1)%20-%202026-08-16; wab_installed_prev=yes
04EvidenceCODE COMPARE
The code that does this

The install/startup fetch is unconditional; a separate, sampled path exists elsewhere

What it actually does
chrome.runtime.onStartup calls the config fetch on every browser startservice-worker.js
// DETECT WHEN CHROME BROWSER LOADS
chrome.runtime.onStartup.addListener( async function (){
	console.log("\ud83d\udd27 [SW DEBUG] Browser startup detected");
	
	if(!SW?.TOTAL_COUNTER?.trk && !SW?.TOTAL_COUNTER?.ads){
		IDB.readTableByKey('totalCounter', `last30Days`, (data) => {
			SW.TOTAL_COUNTER = data || {ads: 0, trk: 0};
			console.log("\ud83d\udd27 [SW DEBUG] Loaded total counter:", SW.TOTAL_COUNTER);
		});
	}
	SW.SERVER_SETTINGS = await SSET.getServerConfigNowAsync();
	SW.USER_SETTINGS = await STORAGE.readAllSettingsAsync();
	SW.WHITELIST = await WLIST.getEffectiveListWithExtra(false);
	SW.HIDDEN_LIST = await HLIST.getUserList();
	
	console.log("\ud83d\udd27 [SW DEBUG] Settings loaded on startup");
	console.log("\ud83d\udd27 [SW DEBUG] Server settings:", SW.SERVER_SETTINGS);
	console.log("\ud83d\udd27 [SW DEBUG] User settings keys:", Object.keys(SW.USER_SETTINGS));
	console.log("\ud83d\udd27 [SW DEBUG] Whitelist:", SW.WHITELIST);
	
	await SW.processWithScripts();
	if ((SW.isInFreeTrial()) || (SW.isRegisteredNotExpired())) {
		console.log("\ud83d\udd27 [SW DEBUG] User is in trial or registered, updating tabs");
		(!TABS.loaded) && TABS.updateTabs();
	} else {
		console.log("\ud83d\udd27 [SW DEBUG] User not in trial/registered, updating tabs with disabled state");
		TABS.updateTabs(false);
		TOTALS.forceExpiredIcon();
	}
	// SET OUR UNINSTALL URL
	SW.setUninstallURL();
	if (SW.bDebugMode || COMMON.rand(1, 5) == 5) { // 20% of the time
		LIC.verifyKey(SW);
	}
});
The unconditional fetch used by onStartup and onInstalledmodules/sset.js
SSET.getServerConfigNow = (fn) => {
	console.log('** SSET.getServerConfigNow');
	fetch('https://webadblocker.org/pluginservice-mv3/ajax-getconfig.php')
		.then(response => response.json())
		.then(json => {
			STORAGE.saveSetting('xab_SERVER_SETTINGS',json);
			STORAGE.readSetting('xab_SERVER_SETTINGS',fn);
			if (typeof SW == 'object') {
				SW.updatedServerSettings();
			}
		})
		.catch(error => {
			console.error('error',error);
		});
};
The separate, sampled path used for periodic refreshes elsewhere in the extensionmodules/sset.js
SSET.getServerConfigNonCritical = (nMax) => {
	return new Promise(resolve => {
		// we use -1 as a trick to force pulling from local settings unless it's empty
		if ((COMMON.rand(1,nMax) == nMax) && (nMax != -1)) { // if nMax == 5, then run 20% of the time
			SSET.getServerConfigNow(function(o) {
				resolve(o);
			});
		} else {
			SSET.getLocalSettings(function(o,bEmpty) {
				if (!bEmpty) {
					resolve(o);
				} else {
					SSET.getServerConfigNow(function(o) {
						resolve(o);
					});
				}
			});
		}
	});
};
05EvidenceTHIRD PARTY LIST
External destination
  • webadblocker.org

    Serves the remote configuration that controls the extension's interface and monetization behavior at runtime.

  • keys.webadblocker.org

    Registration and license-verification endpoints returned inside the remote configuration.

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

Web Ad Blocker sends footer-click analytics to meteor4.com

The code sends split-test analytics to meteor4.com when the footer upgrade overlay shows or is clicked.

Passive analysis recorded no traffic since the overlay never appeared, but footer scripts inject on HTTP/HTTPS pages regardless.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You encounter the extension's footer upgrade overlay or click its upgrade button.

The overlay only appears after the extension's install-age, page, license, reminder, and server-setting checks allow it.

The extension did this

The extension sends a split-test analytics event to meteor4.com.

The event names record whether the footer was shown or whether the upgrade button was clicked.

02EvidenceFIELD TABLE
Query fields sent by the tracking request
FieldValueWhy it matters
Footer test bucket
wab-footer-test1Shows which experiment group was associated with your footer overlay.
Interaction event
B - Clicked Upgrade (A)Records what happened in the extension footer, such as the overlay being shown or the upgrade button being clicked.
Fixed flag
yesAdds a constant marker to the request, so every tracked footer event carries the same flag value.
Empty extra field
nf=Leaves an extra request field blank while still including the field name in the URL.
03EvidenceNETWORK CAPTURE
Captured request
GEThttps://meteor4.com/meteor/write?b=wab-footer-test1&ev=B%20-%20Clicked%20Upgrade%20(A)&f=yes&nf=
No response body was recorded; passive browsing did not trigger the footer overlay.
04EvidenceCODE COMPARE
The code that does this

Footer events feed the meteor4.com tracking request

What it actually does
Content scripts are injected on HTTP and HTTPS pagesmanifest.json
"content_scripts": [ {
   "all_frames": false,
   "css": [ "content.css" ],
   "js": [ "modules/jquery-3.6.0.min.js", "modules/common.js", "modules/storage.js", "modules/sset.js", "modules/idb.js", "modules/wlist.js", "modules/hlist.js", "modules/stats.js", "modules/lic.js", "modules/totals.js", "modules/tutorial.js", "modules/notif.js", "modules/foot.js", "modules/head.js", "filters/hosts.js", "filters/sel.js", "filters/extra.js", "filters/fb.js", "filters/yt.js", "filters/search.js", "filters/track.js", "content.js" ],
   "matches": [ "http://*/*", "https://*/*" ],
   "run_at": "document_start"
} ]
The footer display path can log split-test show eventsmodules/foot.js
// called from content.js
FOOT.showFoot = (totals) => {
	var extensionOrigin = 'chrome-extension://' + chrome.runtime.id;
	if (!location.ancestorOrigins.contains(extensionOrigin)) {
		console.log('FOOT: !location.ancestorOrigins.contains(extensionOrigin)');
		let iframe = document.createElement('iframe');
		iframe.setAttribute('id','wab-iframe2');
		// Must be declared at web_accessible_resources in manifest.json
		let sShowFooterC = CONT.SERVER_SETTINGS.SHOW_FOOTER_STRATEGY_C || 'no';
		bShowFooterC = (sShowFooterC == 'yes');
		let sFootOff = CONT.USER_SETTINGS.xab_foot_off || 'no';
		let bFootOff = (sFootOff == 'yes');
		// commented out below so that we always show the older footer (foot.html) for now on 11/6/2024
		//if (bFootOff && bShowFooterC) {
		//iframe.src = chrome.runtime.getURL('/foot2.html');
		//} else {
		//iframe.src = chrome.runtime.getURL('/foot.html');
		//}
		//for testing -- iframe.src = chrome.runtime.getURL('/foot-b.html');
		//for testing -- iframe.style.cssText = 'display:block !important;background:transparent;position:fixed;left:0;width:100%;bottom:0px;height:205px;z-index:2147483647;border:0px;';

		let sShowFooterD = CONT.SERVER_SETTINGS.SHOW_FOOTER_STRATEGY_D || 'no'; // implemented on the server on 11/6/2024
		bShowFooterD = (sShowFooterD == 'yes');
		if (bShowFooterD) { // show split test
			if (COMMON.rand(1,2) == 1) { // condition A (control)
				STATS.track('wab-footer-test1','A - Footer Shown (A)');
				iframe.src = chrome.runtime.getURL('/foot-a.html');
				iframe.style.cssText = 'display:block !important;background:transparent;position:fixed;left:0;width:100%;bottom:0px;height:180px;z-index:2147483647;border:0px;';
			} else { // condition B (test)
				STATS.track('wab-footer-test1','A - Footer Shown (B)');
				iframe.src = chrome.runtime.getURL('/foot-b.html');
				iframe.style.cssText = 'display:block !important;background:transparent;position:fixed;left:0;width:100%;bottom:0px;height:205px;z-index:2147483647;border:0px;';
			}
		} else { // don't show split test
			iframe.src = chrome.runtime.getURL('/foot.html');
			iframe.style.cssText = 'display:block !important;background:transparent;position:fixed;left:0;width:100%;bottom:0px;height:180px;z-index:2147483647;border:0px;';
		}

		//iframe.style.cssText = 'display:block !important;background:transparent;position:fixed;left:0;width:100%;bottom:0px;height:180px;z-index:2147483647;border:0px;';
		document.body.appendChild(iframe);
		let oIframe = document.getElementById('wab-iframe2');
		if (oIframe) {
			console.log('FOOT: grabbed iframe handle');
			setTimeout(function(){
				if (oIframe.contentWindow) {
					updateTotals = async () => {
						CONT.USER_SETTINGS = await STORAGE.readAllSettingsAsync();
						let nTotalAds = (totals && totals.ads) ? totals.ads : 0;
						let nTotalTrackers = (totals && totals.trk) ? totals.trk : 0;
						let nMaxAds = CONT.USER_SETTINGS.xab_max_ads || 0;
						let nMaxTrackers = CONT.USER_SETTINGS.xab_max_trackers || 0;
						nMaxAds = (nMaxAds < nTotalAds) ? nTotalAds : nMaxAds;
						nMaxTrackers = (nMaxTrackers < nTotalTrackers) ? nTotalTrackers : nMaxTrackers;
						nMaxAds = (nMaxAds > COMMON.MAX_TOTAL_AD_COUNT) ? COMMON.MAX_TOTAL_AD_COUNT : nMaxAds;
						nMaxTrackers = (nMaxTrackers > COMMON.MAX_TOTAL_AD_COUNT) ? COMMON.MAX_TOTAL_AD_COUNT : nMaxTrackers;
						STORAGE.saveSetting('xab_max_ads',nMaxAds);
						STORAGE.saveSetting('xab_max_trackers',nMaxTrackers);
						CONT.USER_SETTINGS.xab_max_ads = nMaxAds;
						CONT.USER_SETTINGS.xab_max_trackers = nMaxTrackers;
						oIframe.contentWindow.postMessage({onWABUpdatedMaxCount:{maxAds:nMaxAds,maxTrackers:nMaxTrackers}},'*');
					};
					updateTotals();
				}
			},2000);
		}
	}
};
The footer upgrade button calls the same trackermodules/foot.js
// called from foot.html
FOOT.onUserClickUpgrade = () => {
	let sWhich = 'A';
	if ($('#wabfoot').hasClass('wabfootb')) { // condition B (test)
		STATS.track('wab-footer-test1','B - Clicked Upgrade (B)');
		sWhich = 'B';
	} else { // condition A (control)
		STATS.track('wab-footer-test1','B - Clicked Upgrade (A)');
	}
	FOOT.onUserClickClose();
	window.parent.postMessage({onWABFootUpgrade:true,whichFooter:sWhich},'*');
};

// called from foot.html
FOOT.loadFootPageCode = () => {
	window.addEventListener('message',function(e) {
		let o = event.data;
		(o.onWABUpdatedMaxCount) && FOOT.onUpdatedCount(o.onWABUpdatedMaxCount);
	},false);

	$(document).ready(function() {
		$('#wabfoot #remind').click(function(e) {
			FOOT.onUserClickReminder();
		});

		$('#wabfoot #upgrade').click(function(e) {
			e.preventDefault();
			FOOT.onUserClickUpgrade();
			return false;
		});

		$('#wabfoot #close').click(function(e) {
			e.preventDefault();
			FOOT.onUserClickClose();
			return false;
		});
	});
};
The tracker builds the meteor4.com GET requestmodules/stats.js
var STATS = {}; // feature split test tracking

STATS.track = (sBucket,sEvent) => { // for split tests
	// meteor4.com, owned by webadblocker.org 
	fetch('https://meteor4.com/meteor/write?b=' + '' + encodeURIComponent(sBucket) + '&ev=' + encodeURIComponent(sEvent) + '&f=yes&nf=')
		.then(response => response.text())
		.then(text => {
			console.log('STATS: tracking response text: ',text);
		})
		.catch(error => {
			console.error('error',error);
		});
};
05EvidenceTHIRD PARTY LIST
External destination
  • meteor4.com

    Receives footer split-test analytics. A source comment says this host is owned by webadblocker.org.

Updated 30 September 2026fifcailncnlobddlehplcimgnehnldio