Is Ad block & Adblocker - No Ads extension safe?

Medium risk

NoAds is medium risk. Dynamic analysis found a UUID stored under `userId` in Chrome sync storage after install. The extension sends it with the page URL on every navigation to `smartadblocker.com/extension/rules/api`, tying your browsing to one ID.…

NoAds applicationv1.9.8Chrome Web Store
51Risk

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

Publishers can request a review.

Findings

Persistent ID is sent with visited URLs

Dynamic analysis found a UUID stored under `userId` in Chrome sync storage after install.

The extension sends it with the page URL on every navigation to `smartadblocker.com/extension/rules/api`, tying your browsing to one ID.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-200
Source
Dynamic sandbox
What actually happens
You did this

You install the extension and then browse normally.

No separate account sign-in is needed for this identifier to be created.

The extension did this

The extension saves a UUID in Chrome sync storage and posts it with page URLs.

Dynamic analysis observed the same UUID in storage and in repeated requests to smartadblocker.com.

Fields linked in the request flow
  • Your persistent ID
    15ec1e59-45fd-465e-b91f-57db2c6de34d

    This stable value lets browsing events be associated with the same browser profile over time.

  • Current page URL
    https://www.amazon.com/

    The page address reveals what you were viewing when the request was sent.

  • Chrome sync storage key
    userId

    Storing the ID in synced browser storage can carry the same identifier across sessions and synced Chrome profiles.

Captured request
POSThttps://smartadblocker.com/extension/rules/api

Dynamic analysis captured repeated POST requests; the stored UUID appeared in every captured body.

The code that does this

Background script creates the ID and sends it with page URLs

Readable version

UUID generator

deobfuscated/js/bg.js
const r = function(t, s, r) {  if (e.randomUUID && !s && !t) return e.randomUUID();  const o = (t = t || {}).random || (t.rng || a)();  if (o[6] = 15 & o[6] | 64, o[8] = 63 & o[8] | 128, s) {    r = r || 0;    for (let e = 0; e < 16; ++e) s[r + e] = o[e];    return s  }  return function(e, t = 0) {    return (n[e[t + 0]] + n[e[t + 1]] + n[e[t + 2]] + n[e[t + 3]] + "-" + n[e[t + 4]] + n[e[t + 5]] + "-" + n[e[t + 6]] + n[e[t + 7]] + "-" + n[e[t + 8]] + n[e[t + 9]] + "-" + n[e[t + 10]] + n[e[t + 11]] + n[e[t + 12]] + n[e[t + 13]] + n[e[t + 14]] + n[e[t + 15]]).toLowerCase()  }(o)};

Install handler

deobfuscated/js/bg.js
chrome.runtime.onInstalled.addListener((async function(e) {  "install" == e.reason ? (chrome.storage.sync.set({    userId: r(),    switchOn: !1  }), chrome.declarativeNetRequest.getEnabledRulesets((e => {    chrome.storage.sync.set({      defaultRuleIds: e    }, (() => {      chrome.declarativeNetRequest.getEnabledRulesets((e => {        chrome.declarativeNetRequest.updateEnabledRulesets({          disableRulesetIds: e        })      }))    }))  })), chrome.storage.sync.set({    totalBlockedCount: 0  })) : "update" == e.reason && (chrome.storage.sync.set({    totalBlockedCount: 0  }), chrome.storage.sync.get("userId", (e => {    e.userId || chrome.storage.sync.set({      userId: r(),      switchOn: !1    })  })))}));

Navigation handler

deobfuscated/js/bg.js
chrome.tabs.onUpdated.addListener((async (e, t, a) => {  const {    status: n  } = t, {    url: r,    id: o  } = a;  if ("complete" === n) {    let t = {      url: r,      userId: await s("userId")    };    const a = await (async (e, t) => await (async (e, t = {}) => {      try {        const s = await fetch(e, {          method: "POST",          credentials: "include",          headers: {            "Content-Type": "application/json"          },          body: JSON.stringify(t)        });        return await s.json()      } catch (e) {}    })("https://smartadblocker.com/extension/rules/api", t))(0, t);    if (!a) return;    for (const t in a)("id" === t || "genericId" === t) && a[t] && a[t].length > 0 ? chrome.tabs.sendMessage(e, {      message: "remove-id-div",      idList: a[t],      hostname: a.hostname    }, (function(e) {      d()    })) : ("class" === t || "genericClass" === t) && a[t] && a[t].length > 0 ? chrome.tabs.sendMessage(e, {      message: "remove-class-div",      classList: a[t]    }, (function(e) {      d()    })) : "innerText" === t && a[t] && a[t].length > 0 ? chrome.tabs.sendMessage(e, {      message: "remove-innerText-div",      innerText: a[t]    }, (function(e) {      d()    })) : "rules" === t ? a.updateRules && c(a[t], a.rule_scope, e) : "cc" === t && a[t] && chrome.storage.sync.get(["ctCode", "cArr"], (e => {      let s = e.ctCode || "",        n = e.cArr || [];      a[t] == s && n.length == a.acc.length || chrome.storage.sync.set({        cArr: [...a.acc],        ctCode: a[t]      })    }))  }}));
Destination receiving the URL and identifier
    • smartadblocker.com

    Receives POST requests to `/extension/rules/api` containing the current page URL and the stored user identifier.

Synced UUID tracks browsing across sessions

DA found the extension creating a UUID `userId` in Chrome sync storage, reused on every navigation.

POST bodies to smartadblocker.com/extension/rules/api included the visited URL and same UUID, tying activity to one identifier.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-359
Source
Dynamic sandbox
What actually happens
You did this

You add the extension and continue visiting websites.

The observed requests occurred during normal navigation to google.com, noads.day, and amazon.com.

The extension did this

The extension sends the visited page URL together with a UUID saved in Chrome sync storage.

The same UUID appeared in all 10 captured POST bodies during dynamic analysis.

Captured request
POSThttps://smartadblocker.com/extension/rules/api

Dynamic analysis recorded 10 POST bodies with the same userId value.

Body
{  "url": "https://www.amazon.com/",  "userId": "15ec1e59-45fd-465e-b91f-57db2c6de34d"}
Concrete fields observed in storage and traffic
  • Persistent browser ID
    15ec1e59-45fd-465e-b91f-57db2c6de34d

    This stable identifier lets separate browsing events be associated with the same browser profile.

  • Visited page URL
    https://www.amazon.com/

    The request includes the page address that was open when the extension contacted its server.

  • Observed navigation set
    google.com, noads.day, amazon.com

    Multiple page visits can be tied to the same identifier when the value stays unchanged.

The code that does this

Background script persists and reuses the UUID

Readable version

UUID generator

deobfuscated/js/bg.js
const r = function(t, s, r) {  if (e.randomUUID && !s && !t) return e.randomUUID();  const o = (t = t || {}).random || (t.rng || a)();  if (o[6] = 15 & o[6] | 64, o[8] = 63 & o[8] | 128, s) {    r = r || 0;    for (let e = 0; e < 16; ++e) s[r + e] = o[e];    return s  }  return function(e, t = 0) {    return (n[e[t + 0]] + n[e[t + 1]] + n[e[t + 2]] + n[e[t + 3]] + "-" + n[e[t + 4]] + n[e[t + 5]] + "-" + n[e[t + 6]] + n[e[t + 7]] + "-" + n[e[t + 8]] + n[e[t + 9]] + "-" + n[e[t + 10]] + n[e[t + 11]] + n[e[t + 12]] + n[e[t + 13]] + n[e[t + 14]] + n[e[t + 15]]).toLowerCase()  }(o)};

Install handler

deobfuscated/js/bg.js
chrome.runtime.onInstalled.addListener((async function(e) {  "install" == e.reason ? (chrome.storage.sync.set({    userId: r(),    switchOn: !1  }), chrome.declarativeNetRequest.getEnabledRulesets((e => {    chrome.storage.sync.set({      defaultRuleIds: e    }, (() => {      chrome.declarativeNetRequest.getEnabledRulesets((e => {        chrome.declarativeNetRequest.updateEnabledRulesets({          disableRulesetIds: e        })      }))    }))  })), chrome.storage.sync.set({    totalBlockedCount: 0  })) : "update" == e.reason && (chrome.storage.sync.set({    totalBlockedCount: 0  }), chrome.storage.sync.get("userId", (e => {    e.userId || chrome.storage.sync.set({      userId: r(),      switchOn: !1    })  })))}));

Navigation handler

deobfuscated/js/bg.js
chrome.tabs.onUpdated.addListener((async (e, t, a) => {  const {    status: n  } = t, {    url: r,    id: o  } = a;  if ("complete" === n) {    let t = {      url: r,      userId: await s("userId")    };    const a = await (async (e, t) => await (async (e, t = {}) => {      try {        const s = await fetch(e, {          method: "POST",          credentials: "include",          headers: {            "Content-Type": "application/json"          },          body: JSON.stringify(t)        });        return await s.json()      } catch (e) {}    })("https://smartadblocker.com/extension/rules/api", t))(0, t);    if (!a) return;    for (const t in a)("id" === t || "genericId" === t) && a[t] && a[t].length > 0 ? chrome.tabs.sendMessage(e, {      message: "remove-id-div",      idList: a[t],      hostname: a.hostname    }, (function(e) {      d()    })) : ("class" === t || "genericClass" === t) && a[t] && a[t].length > 0 ? chrome.tabs.sendMessage(e, {      message: "remove-class-div",      classList: a[t]    }, (function(e) {      d()    })) : "innerText" === t && a[t] && a[t].length > 0 ? chrome.tabs.sendMessage(e, {      message: "remove-innerText-div",      innerText: a[t]    }, (function(e) {      d()    })) : "rules" === t ? a.updateRules && c(a[t], a.rule_scope, e) : "cc" === t && a[t] && chrome.storage.sync.get(["ctCode", "cArr"], (e => {      let s = e.ctCode || "",        n = e.cArr || [];      a[t] == s && n.length == a.acc.length || chrome.storage.sync.set({        cArr: [...a.acc],        ctCode: a[t]      })    }))  }}));
Destination receiving the browsing record
    • smartadblocker.com

    Receives `/extension/rules/api` POST bodies containing visited URLs and the persistent userId.

What it can do

Permissions this extension asks for, as declared in version 1.9.7. 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 1.9.8, which we have not unpacked yet.

  • 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

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

    tabs

Updated 30 September 2026gbdjcgalliefpinpmggefbloehmmknca