Is Total Adblock - Ad Blocker safe?

Medium risk

Total Adblock is medium risk. Loading a Total Adblock/TotalAV account page with an active session, or right after install auto-creates one, sends the `LC` cookie to totaladblock.protected.net/v1/auth/cookie. The backend replies with the account record and a login link.…

Protected.netv5.13.0Chrome Web Store
52Risk
Who publishes it

Total Security Limited - 6 other listings from the same operator, none carrying a finding

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

Publisher
Protected.net
Declared legal entity
Total Security Limited
Registered address
16-18 Barnes Wallis Road, Fareham PO15 5TT, GB
Registered contact
Total Security Limited

Same store account

4 other listings published from this account, 132k+ users between them, none of them carrying a finding.

Same operator - 2 listings

Published under a different store account, but sharing the registered address, contact or declared legal entity this one gave the store.

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

Publishers can request a review.

Findings

Reads your account login cookie and sends it to the backend automatically

Loading a Total Adblock/TotalAV account page with an active session, or right after install auto-creates one, sends the `LC` cookie to totaladblock.protected.net/v1/auth/cookie.

The backend replies with the account record and a login link.

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

You have an active login session on a Total Adblock or TotalAV website and open one of the vendor's own account pages.

This also runs immediately after the extension creates an account for you on install, since that step leaves the same session cookie in place.

The extension did this

The extension reads that site's session cookie and sends the full value to the vendor's backend, which logs the browser in and returns the account record.

We observed this during dynamic analysis: the backend answered with the complete account record and a login link, with no click or prompt shown to you.

What gets read from your browser and sent to the backend
  • Your account session cookie (LC)
    <redacted — RSA-signed session token>

    This is the login token for the Total Adblock/TotalAV website you're signed into. Anyone who has it can act as that logged-in session.

  • Email decoded from the cookie
    X-Email: alex.morgan@example.com (illustrative)

    When the extension can pull an email address out of the cookie, it repeats that address in a request header.

  • Account record returned by the server
    user, plan, authToken, ssoLoginUrl

    The response you get back contains your plan, account identifiers, and a link that signs the browser in automatically.

Captured request
POSThttps://totaladblock.protected.net/v1/auth/cookie

Returned HTTP 200 with the account's user record, plan, and a pre-authenticated login URL. Observed during dynamic analysis after navigating to a Total Adblock account page with an existing login session in place.

Body
{  "cookie": "<redacted>"}
The code that does this

The two cookie-read entry points and the shared upload function, shipped vs. deobfuscated.

Readable version

Install-time auto-login, readable

// OnInstalled.autoLogin() — reads the LC session cookie from the brand's// own domain and its parent brand domain, then hands it to authenticateWithCookieautoLogin() {  return new Promise((resolve) => (async () => {    log(AUTO_SIGNUP, "Requesting LC cookies for primary and parent domains (using browser API)");    Promise.all(      this.getAutoLoginCookieDomains().map((url) => Cookies.get({ name: "LC", url }))    ).then(async (cookies) => {      log(AUTO_SIGNUP, "Request for login cookies succeeded", cookies);      const found = cookies.find((c) => c && c.value);      if (!found) {        log(AUTO_SIGNUP, "No login cookies found.");        return resolve(null);      }      log(AUTO_SIGNUP, "Cookie found so attempting authentication.", found);      UserStore.authenticateWithCookie(found.value).then(async (session) => {        log(AUTO_SIGNUP, "Successfully authed through API using cookie");        // ...fetches existing rating, then resolve(session)...      }).catch(() => resolve(null));    }).catch(async () => {      log(AUTO_SIGNUP, "Failed to get login cookies through browser API.");      resolve(null);    });  })());}getAutoLoginCookieDomains() {  return [Brand.www(), Brand.wwwParent()]; // e.g. www.totaladblock.com, www.totalav.com}

Navigation handler, readable

// tabs.onUpdated: on every completed page load, check whether the page// is one of the brand's own account pages; if so, re-check and re-send// the session cookie so a just-upgraded account gets logged inbrowser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => (async () => {  if (tab.status !== "complete" || !tab.url) return;  await Store.ensureStoreExists();  if (Account.isPaid() || this.loggingIntoPaidAccount || Account.isPollingForUpdatesAfterPayment()) return;  const url = tab.url.split("?")[0];  const scheme = ["prod", "qa"].includes(Brand.getEnv()) ? "https" : "http";  const matchedAccountPages = [    `${scheme}://my.${Brand.getBrandDomain()}/`,    `${scheme}://my.${Brand.getParentBrandDomain()}/`,    `${scheme}://av.${Brand.getBrandDomain()}/`,    `${scheme}://adblock.${Brand.getParentBrandDomain()}/`,    `${scheme}://adblock.${Brand.getBrandDomain()}/`,    `${scheme}://shield.${Brand.getBrandDomain()}/`,    `${scheme}://shield.${Brand.getParentBrandDomain()}/`,    `${scheme}://browser.${Brand.getBrandDomain()}/`,    `${scheme}://dashboard.${Brand.getBrandDomain()}/`,    `${scheme}://dashboard.${Brand.getParentBrandDomain()}/`,  ];  if (matchedAccountPages.includes(url)) {    const cookieUrl = `${scheme}://${Brand.getHostname(url)}`;    Cookies.get({ name: "LC", url: cookieUrl }).then(async (cookie) => {      if (cookie && (await UserStore.getAccountStatusFromJwt(cookie.value)) !== AccountStatus.FREE) {        this.loggingIntoPaidAccount = true;        Account.clear(); TabState.clear(); Popup.clear();        UserStore.authenticateWithCookie(cookie.value).then(() => {          UserStore.resetRatingPromptDismissals();          this.postLoggedIntoPaidAccount();          UserStore.syncRating().finally(() => { this.loggingIntoPaidAccount = false; });        });      }    });  }})());

Shared upload function, readable

// UserStore.authenticateWithCookie — sends the raw session cookie value// to the backend and stores whatever account/token it gets backstatic async authenticateWithCookie(cookieValue) {  const body = { cookie: decodeURIComponent(cookieValue) };  const email = this.getEmailFromLoginCookie(cookieValue);  if (email) body["X-Email"] = email;  const res = await Http.post(Routes.api("/v1/auth/cookie"), body);  return this.handleAuthResponse(await res.json(), "auth");}
Where the session cookie is sent
    • totaladblock.protected.net

    Operator API that receives the full session cookie and returns the account record and login link. Operated by the Total Adblock / TotalAV vendor (Protected.net).

Registers an account with generated credentials on install, no consent

If you've never signed in, Total Adblock auto-registers an account: a disposable {random}@protected-signup.com email and password, POSTed with your browser and language to totaladblock.protected.net/v1/user, seconds after install.

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

You install Total Adblock and have not previously signed in to the vendor's sites.

No 'LC' login cookie exists on totaladblock.com or totalav.com, so the auto-login path finds nothing.

The extension did this

The extension generates an email and password and registers an account on your behalf with its operator.

It posts the generated credentials, your browser name, and your interface language to totaladblock.protected.net/v1/user and saves the returned authentication token to local storage.

What the registration request contains
  • A generated email address
    DaKpLYAkWa_1781802160179@protected-signup.com

    A made-up address combining a random string with the install moment. Not your real email, but a stable identifier tied to your install.

  • A generated password
    k7Qp2mZ9rXa4Lb8vNc1W

    A random 20-character password created for the account and sent to the server.

  • Your browser name
    Chrome Browser

    Which browser you are running, transmitted as the account's device name.

  • Your interface language
    en

    The language your browser is set to, which can indicate your region.

  • Free-trial flag
    requestTrial: true

    A flag asking the server to open a free trial against the new account.

Captured request
POSThttps://totaladblock.protected.net/v1/user

Returned HTTP 200 with an authentication token, which was then written to local storage. Observed during dynamic analysis to fire on install with no user interaction; reproduced across two independent sessions, each generating a different email.

Headers
X-Email
DaKpLYAkWa_1781802160179@protected-signup.com
Content-Type
application/json
Body
{  "name": "Total Adblock User",  "email": "DaKpLYAkWa_1781802160179@protected-signup.com",  "password": "<redacted>",  "language": "en",  "challengeToken": "<challenge token>",  "deviceName": "Chrome Browser",  "requestTrial": true}
The code that does this

The gate-and-register logic from the shipping source.

Readable version

The login-or-register branch

// onInstalled (reason === 'install')let session = await this.autoLogin();          // reads 'LC' cookie on brand domainsif (!session) session = await this.signup();   // none found -> register a new account

The signup body and token persistence

// UserStore.signup() — generates and registers an accountstatic async signup(name, email, password) {  const challenge = await this.challenge();  const rand = Random.random();  const ts = Date.now();  const local = encodeURIComponent(`${rand}_${ts}`);  name     = name     || `${Brand.getDisplayName()} User`;  email    = email    || `${local}@protected-signup.com`;  password = password || Random.password(20);  const res = await Http.post(Routes.api('/v1/user'), {    name, email, password,    language: Lang.getUiLanguage(),    challengeToken: challenge.challengeToken,    deviceName: `${Browser.getBrowserName()} Browser`,    requestTrial: true  }, { 'X-Email': email });  const body = await res.json();  await Storage.set({    FREE_TRIAL_AUTH_TOKEN: getByKeyPath('data:response:authToken', body)                        || getByKeyPath('data:response:token', body),    FREE_TRIAL_EMAIL: getByKeyPath('data:user:email', body)  });  this.reloadLander();  return this.handleAuthResponse(body, 'signup');}
Where the generated account data is sent
    • totaladblock.protected.net

    Operator API receiving the auto-registered account and returning the authentication token. Operated by the Total Adblock / TotalAV vendor (Protected.net).

Auto-creates an account and posts generated credentials on install

On install, Total Adblock's worker auto-creates an account: a throwaway email ({random}_{timestamp}@protected-signup.com) and random password POSTed to totaladblock.protected.net/v1/user.

Confirmed within seconds; token saved locally.

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

You install Total Adblock for the first time.

You take no further action, no sign-up form is shown and no button is clicked.

The extension did this

The extension generates a disposable email and random password and registers an account for you with its operator.

It then posts those generated credentials, your browser name, and your interface language to totaladblock.protected.net/v1/user and stores the returned authentication token locally.

What gets sent to the operator when the account is auto-created
  • A generated email address
    DaKpLYAkWa_1781802160179@protected-signup.com

    A throwaway address the extension makes up, combining a random string and install time. Not real, but a persistent identifier for install.

  • A generated password
    k7Qp2mZ9rXa4Lb8vNc1W

    A random 20-character password created for the account. It is sent to the server and the account it unlocks is tied to your install.

  • Account display name
    Total Adblock User

    A fixed display name derived from the product brand.

  • Your browser name
    Chrome Browser

    Which browser you are running, sent as the device name for the account.

  • Your interface language
    en

    The language your browser UI is set to, which can hint at your region.

  • Free-trial flag
    requestTrial: true

    A flag requesting that a free trial be opened against the new account.

Captured request
POSThttps://totaladblock.protected.net/v1/user

Returned HTTP 200 with an authentication token. The token was then written to local storage. Observed during dynamic analysis to fire within seconds of a fresh install with no user interaction; behaviour reproduced across two independent sessions, each producing a different generated email.

Headers
X-Email
DaKpLYAkWa_1781802160179@protected-signup.com
Content-Type
application/json
Body
{  "name": "Total Adblock User",  "email": "DaKpLYAkWa_1781802160179@protected-signup.com",  "password": "<redacted>",  "language": "en",  "challengeToken": "<challenge token>",  "deviceName": "Chrome Browser",  "requestTrial": true}
The code that does this

The account-creation code from the extension's shipping source.

Readable version

onInstalled: if no login cookie, sign up automatically

// background.min.js onInstalled handler (reason === 'install')async onInstalled(details) {  if (details.reason === 'install') {    await this.setInitialSettings();    let session = await this.autoLogin();        // looks for an 'LC' login cookie    if (!session) session = await this.signup(); // no cookie -> create an account    // ...onboarding + lander...  }}

The signup body assembler and token persistence

// UserStore.signup() — generates credentials and registers the accountstatic async signup(name, email, password) {  const challenge = await this.challenge();  const rand = Random.random();  const ts = Date.now();  const local = encodeURIComponent(`${rand}_${ts}`);  name     = name     || `${Brand.getDisplayName()} User`;     // 'Total Adblock User'  email    = email    || `${local}@protected-signup.com`;      // generated address  password = password || Random.password(20);                  // random 20-char password  const res = await Http.post(Routes.api('/v1/user'), {    name, email, password,    language: Lang.getUiLanguage(),    challengeToken: challenge.challengeToken,    deviceName: `${Browser.getBrowserName()} Browser`,    requestTrial: true  }, { 'X-Email': email });  const body = await res.json();  await Storage.set({    FREE_TRIAL_AUTH_TOKEN: getByKeyPath('data:response:authToken', body)                        || getByKeyPath('data:response:token', body),    FREE_TRIAL_EMAIL: getByKeyPath('data:user:email', body)  });  this.reloadLander();  return this.handleAuthResponse(body, 'signup');}
Where the generated credentials are sent
    • totaladblock.protected.net

    Operator API receiving the auto-created account (email, password, browser, language) and returning the auth token. Operated by the Total Adblock/TotalAV vendor (Protected.net).

Updated 30 September 2026gekdekpbfehejjiecgonmgmepbdnaggp