Is Adblocker Fortify safe?

Critical risk

Adblocker Fortify is critical risk. Adblocker Fortify fetches a config object listing which sites get extra injected scripts. The operator can add or remove target sites anytime, with no visible update. The injected script, block.js, runs inside every targeted page.…

adblockerfortifyv1.0.4Chrome Web Store
97Risk

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

Publishers can request a review.

Findings

Server controls which websites receive injected scripts via remote config

CriticalunwantedCWE-829Dynamic sandbox

Adblocker Fortify fetches a config object listing which sites get extra injected scripts.

What actually happens

You did this

The content script loads on every page visit.

contentScript.js runs at document_start on <all_urls> (manifest content_scripts declaration).

The extension did this

The script reads a server-provided configuration and, when the current site matches an operator-specified entry, injects block.js into the page.

function c() creates a script element, sets its src to chrome.runtime.getURL(opts.opts[i][19]), and appends it to document.head. Target sites are specified in opts.opts[i][21], received from the remote config endpoint.

The code that does this

Config sync and script injection (background.js + contentScript.js)

Readable version

prefManager.sync() — config fetch

background.js
async sync(token) {  try {    // Fetch: https://adblockerfortify.com/opts/?token=<opt>    const data = await fetch(u.opts + token).then(r => r.json());    // Store full response object as 'opts' in chrome.storage.local    await chrome.storage.local.set({ opts: data });  } catch (e) { throw e; }}

contentScript.js — per-page injection loop

contentScript.js
function injectScriptForConfig(configArray, index, configRoot) {  // Create element of server-specified type (e.g. 'script')  let el = document.createElement(configArray[index][18]);  // Set src to extension's block.js URL  el.src = chrome.runtime.getURL(configArray[index][19]);  document.head.appendChild(el);}function processOpts(opts) {  const targets = opts.opts[7]; // server-specified index list  if (!Array.isArray(targets)) return;  targets.forEach(index => {    const targetSites = opts.opts[index][21]; // hostname(s) for this entry    if (currentHostnameMatches(targetSites)) {      injectScriptForConfig(opts.opts, index, opts);    }  });}// Runs on every page loadchrome.storage.local.get(['opts']).then(store => {  if (store.opts) processOpts(store);});

Remote configuration source

    • adblockerfortify.com

    Developer-controlled server; issues per-install tokens via /new and delivers per-install site injection config via /opts/?token=<opt>.

What block.js does on injected pages

block.js contains an element-picker overlay (for user-triggered ad removal) and reads additional configuration from its own script element's data attributes. The operator's ability to control which sites receive this script via server config means the injection target list can change at any time without a CWS update.

Ad-blocker fetches and applies network rules from remote server every hour

HighunwantedCWE-829Dynamic sandbox

Adblocker Fortify fetches rules from the developer's server every 60 minutes via a per-install token.

What actually happens

You did this

A Chrome alarm fires 60 minutes after install and every 60 minutes thereafter.

The alarm named 'updateNetRulesAlarm' is registered during installation in NetworkManager.setupUpdateAlarm().

The extension did this

The extension downloads a rule set from the developer's server and replaces all of Chrome's dynamic blocking rules with the server's response.

chrome.declarativeNetRequest.updateDynamicRules() removes all current dynamic rules and applies the server-provided array without any local schema check or size limit.

Captured request

GEThttps://adblockerfortify.com/opts/all/?token=a3f8c12d-7b41-4e09-a1dc-82f0e3c94b17

JSON array of declarativeNetRequest rule objects; content varies per server response.

The code that does this

Rule fetch and apply loop (background.js lines 38-66)

Readable version
async updateNetworkData() {  const { lastUpdateTimestamp: e } = await chrome.storage.local.get({ lastUpdateTimestamp: 0 });  if (!(e && Date.now() - e < this.ms)) {    // Build URL: https://adblockerfortify.com/opts/all/?token=<opt>    const url = await this.addNetworkParams(this.durl + '/opts/all/');    const response = await fetch(url);    const rules = await response.json();    // Replace ALL dynamic rules with server-supplied set    await this.updateNetworkItem(rules);  }}async updateNetworkItem(e) {  // ...  const existing = await chrome.declarativeNetRequest.getDynamicRules();  const removeIds = existing.map(r => r.id);  await chrome.declarativeNetRequest.updateDynamicRules({    removeRuleIds: removeIds,    addRules: [...serverRules, ...preservedHighPriorityRules]  });}

Remote rule source

    • adblockerfortify.com

    Developer-controlled server that issues per-install tokens and delivers JSON rule sets applied directly to Chrome's declarativeNetRequest engine.

When this fires

Every 1 hour

Rule update fires every 60 minutes after install via a Chrome alarm named 'updateNetRulesAlarm'.

Per-install tracking token sent on every config and rule update

MediumunwantedCWE-359Dynamic sandbox

On install, Adblocker Fortify gets a unique token from adblockerfortify.com, stored permanently.

What actually happens

You did this

You install Adblocker Fortify.

The extension did this

The extension fetches a unique token from adblockerfortify.com and stores it permanently.

From that point on, every request the extension makes to its update server includes this token as a query parameter, allowing the server to track that installation across all future update checks.

Captured request

GEThttps://adblockerfortify.com/opts/all/?token=ai9WZkg2SXJUU20veDY0QTU5UmhKeUhYM0p2UU1NR0I3bldwa2YwK2tCWkY4c0R3SjhOTnp4Mnd4R3dMdUFjakt1ckNlYnpn

200 OK, returns JSON array of declarativeNetRequest rules applied as dynamic ad-blocking rules

What the token request reveals to the server

  • Your installation token
    ai9WZkg2SXJUU20veDY0QTU5UmhKeUhYM0p2UU1NR0I3bldwa2YwK2tCWkY4c0R3SjhOTnp4Mnd4R3dMdUFjakt1ckNlYnpn

    A unique value assigned to your installation. It doesn't change between sessions or updates; every future request carries it.

  • Request timestamp
    2026-04-18T02:47:55Z

    The server receives each update check as it happens, building a timeline of when your browser was active with the extension running.

  • Your IP address
    93.184.216.34

    Each request exposes the IP your browser is using then. Combined with the token, this links your IP history to your install.

The code that does this

The token assignment and attachment logic in background.js

Readable version

Token fetch on install

// On first install, request a unique token from the serverconst response = await fetch('https://adblockerfortify.com/new');const data = await response.json();chrome.storage.local.set({  opt: data.opt,          // store the unique token  range: data.range ?? 7200}, () => {  prefManager.schedule(data.range ?? 7200);  // token is also embedded in the uninstall URL so the server  // knows when this specific installation is removed  chrome.runtime.setUninstallURL(data.del + data.opt);  updateNetworkData();});

Token appended to all update requests

// Reads the stored token and appends it to any URL passed inasync function addNetworkParams(url) {  return url + '?token=' + await getCachedToken();}async function getCachedToken() {  // In-memory cache so storage isn't hit on every request  if (!this.tokenCache) {    const result = await chrome.storage.local.get(['opt']);    this.tokenCache = result.opt;  }  return this.tokenCache;}

Periodic rule update (fires every 60 minutes)

async function updateNetworkData() {  const { lastUpdateTimestamp } = await chrome.storage.local.get({ lastUpdateTimestamp: 0 });  // Skip if updated within the last 24 hours (this.ms = 864_000_000 ms)  if (lastUpdateTimestamp && Date.now() - lastUpdateTimestamp < this.ms) return;  // Token is appended here — every rule fetch goes out with ?token=<opt>  const urlWithToken = await this.addNetworkParams('https://adblockerfortify.com/opts/all/');  const response = await fetch(urlWithToken);  const rules = await response.json();  await this.updateNetworkItem(rules);  await chrome.storage.local.set({ lastUpdateTimestamp: Date.now() });}

What's stored on your device

The per-install token, written on first install, is never cleared; every future request includes it. Two test installs got different tokens.

Location
chrome.storage.local key 'opt'
Contents
ai9WZkg2SXJUU20veDY0QTU5UmhKeUhYM0p2UU1NR0I3bldwa2YwK2tCWkY4c0R3SjhOTnp4Mnd4R3dMdUFjakt1ckNlYnpn

Where the token is sent

    • adblockerfortify.com

    The extension's update server. Receives the token on every rule/config request, issues it on install, and gets an uninstall notice via setUninstallURL.

What it can do

Permissions this extension asks for, as declared in version 1.0.4. 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>

  • Block and redirect the requests your browser makes

    declarativeNetRequest

  • See which of your requests its blocking rules matched

    declarativeNetRequestFeedback

  • Store data in your browser

    storage

  • Act on the current tab, but only after you click the extension

    activeTab

  • See the address and title of every tab you have open

    tabs

  • Schedule its own background tasks

    alarms

  • Store an unlimited amount of data in your browser

    unlimitedStorage

  • Watch every request your browser makes

    webRequest

Updated 30 September 2026mhlppgemmcdfjonomcbgfddlgcjnghga