Is Privacy Test safe?

Low risk

Privacy Test is low risk. Code analysis shows a message handler reachable from hotcleaner.com and two sibling extension ids can list every installed extension, then turn any of them on or off except a 16-hash vendor allowlist, without a click on the target.

www.hotcleaner.comv10.7Chrome Web Store
20Risk
Who publishes it

www.hotcleaner.com - 1 other listing from the same operator, 1 of them carrying a finding

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

Same store account

1 other listing published from this account, 1.0M+ users between them. 1 of them carries a finding.

Shared hosts - 1 hostname

Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.

api64.com
Also called by 3 other listings, including Magic Actions for YouTube

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

Publishers can request a review.

Findings

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-940
SourceAI FOUND

Privacy Test can enable or disable any other installed extension with no click

Code analysis shows a message handler reachable from hotcleaner.com and two sibling extension ids can list every installed extension, then turn any of them on or off except a 16-hash vendor allowlist, without a click on the target.

01EvidenceCAUSE EFFECT
What actually happens
You did this

A script on hotcleaner.com sends the extension a message naming another installed extension and asking it to disable that extension.

The same message API also accepts a request from either of two sibling extension ids listed in the manifest.

The extension did this

The extension hashes the id against a 16-value allowlist, then calls chrome.management.setEnabled(id, false), turning off that extension with no click recorded on it.

The same handler also enables extensions and returns the full installed-extension list on a separate message code.

02EvidenceFIELD TABLE
What the externally_connectable bridge reads and controls
FieldValueWhy it matters
Installed extension list
uBlock Origin (enabled), Malwarebytes Browser Guard (enabled), 36 moreEvery extension installed in your browser, with its name, icon, version and on or off state.
Extension id to enable
{i:233, r:'cjpalhdlnbpafiamejdnhcphjbkeiagm'}The 32-character id of an installed extension to turn back on.
Extension id to disable
{i:377, r:'cjpalhdlnbpafiamejdnhcphjbkeiagm'}The 32-character id of an installed extension to turn off, unless it is on the 16-hash allowlist.
03EvidenceCODE COMPARE
The code that does this

The onMessageExternal handler and the integrity check it consults

What it actually does
SW_JS_ID.js:74-87, the onMessageExternal dispatcherSW_JS_ID.js
  f.onMessageExternal.addListener((a, d, b) => {
    "function" === typeof b && (34 === a?.i ? v().then(b).catch(b) : 55 === a?.i ? (m = d.tab && d.tab.id, h = 1, k({
        url: "APPS_HTML_ID.html",
        active: !0,
        pinned: !0,
        index: 999
      }).then(b).catch(b)) : 89 === a?.i ? b(h) : a?.r?.match(/[a-z]{32}/) ? 144 === a?.i ?
      u(a.r).then(b).catch(b) : 233 === a?.i ? p(a.r, !0).then(b).catch(b) : 377 === a?.i ? (self.checkIntegrity || self.importScripts("DIR_JS/INTEGRITY_JS_ID.js"), self.checkIntegrity(a.r, g => {
        g ? b("prohibited") : p(a.r, !1).then(b).catch(b)
      })) : b() : n.get("installed").then(g => {
        g.v = "10.7";
        b(g)
      }).catch(b))
  })
// v = getAll, u = management.get, p = management.setEnabled
INTEGRITY_JS_ID.js:5-18, the allowlist checkDIR_JS/INTEGRITY_JS_ID.js
  const e = "9a42ee1af01ec0451057571887781d29d9c1fb5afe8d4d1593ffbb88722fe537 03700647745892f9bcfe30d98e3894b0a205174c55050ed91cdf560a39cf6411 738625b9eedf5a4c6affee51b9c5719aa7f49c61ecf6e6f289f8902986b8eb18 5263cd497bbd7c3778321f66a0f4d84aa8d2c3d07fe8da775bfeeee821c5776f c191260b18d2fdb9c02daca261d3bbb89420ae58a8bb531d60a360511e4fa93f 0da27abe045219c3dfa1f435b15f2303d8cca4bd7b132215cab44bd84eb8b749 a9727b4400aaeddc35467418e9f86645a0fabe937c4893b74db0179f00bf4e43 f49d4a185182a49c06126ab4b824c4446fa53049587f2bf80543ac27232a2821 e36f3e98826ce29d2ab2db4bb3ed057989324cfefdb9fc9fbdcf9afc50752d38 f7b7b5a0b491cfc7d745ac42391befff9078291b3c95b6fc0d100d2224c5c76a 7ad8051bff057cc24c7a07c57110b3f0354be2672d5c0c589d5a482ab4d11268 e36f3e98826ce29d2ab2db4bb3ed057989324cfefdb9fc9fbdcf9afc50752d38 96426a01ea21c7cbd530fb3db9124723099643c932d078510899d5e2fdb7e3a4 aa96eca7e33b5d3caa36769214b199d02872094171c7c482056c395a16432bf2 5667eef14bfab30fe85b3ad1313f7751f9e3916245878dc7b87b9c98d90231a0 2785c2f995b9e0e7f2e13254448ba425d82b0001c1f57ce875f22f36cfa44f04".split(" "), // 16 hardcoded SHA-256 hashes, verbatim
    g = (c, a) => {
      let b = (new TextEncoder).encode(c);
      crypto.subtle.digest("SHA-256", b).then(d => {
        b = new Uint8Array(d);
        d = Array.from(b);
        a(d.map(f => f.toString(16).padStart(2, "0")).join(""))
      }).catch(d => a(!1))
    },
    h = (c, a) => {
      chrome.runtime.id == c ? a(!0) : g(c, b => {
        a(e.includes(b))
      })
    };
// h(targetId, cb) = self.checkIntegrity; cb(true) only for this extension's own id or an allowlisted hash
04EvidenceARTIFACT
Reproduce it yourself

Confirms whether the bridge will list installed extensions and toggle one that is not on the vendor allowlist.

RequiresChrome or Edge with Privacy Test (jecjpgpgafmabefacgcfggpofndpbdod) installedA second, disposable test extension whose id you control
check-management-bridge.js · js
// Run in the DevTools console of a tab on https://www.hotcleaner.com/
// (or from any extension's own console using chrome.runtime.sendMessage
// with this extension's id as the first argument).
const PRIVACY_TEST_ID = 'jecjpgpgafmabefacgcfggpofndpbdod';

// Optional: id of a second, disposable extension you installed for this test.
const TEST_EXTENSION_ID = 'REPLACE_WITH_A_TEST_EXTENSION_ID';

function send(payload) {
  return new Promise((resolve) => {
    chrome.runtime.sendMessage(PRIVACY_TEST_ID, payload, resolve);
  });
}

(async () => {
  const list = await send({ i: 34 });
  console.log('Installed extensions returned:', Array.isArray(list) ? list.length : list);

  if (TEST_EXTENSION_ID !== 'REPLACE_WITH_A_TEST_EXTENSION_ID') {
    const disableResult = await send({ i: 377, r: TEST_EXTENSION_ID });
    console.log('Disable result:', disableResult);
    console.log('Check chrome://extensions - the test extension should now be off with no click on it.');

    const enableResult = await send({ i: 233, r: TEST_EXTENSION_ID });
    console.log('Enable result:', enableResult);
  }
})();
How to run it
  1. 1
    Install a disposable test extension and copy its 32-character id.
  2. 2
    Paste this script into DevTools on hotcleaner.com and set TEST_EXTENSION_ID.
  3. 3
    Run it and watch chrome://extensions toggle with no click.
05EvidencePLAIN NOTE
Observation

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.

What it can do

Permissions this extension asks for, as declared in version 10.7. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.

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

    activeTab

  • See, disable and uninstall your other extensions, including your security ones

    management

  • Change your browser's privacy and security settings

    privacy

  • Run its own code inside the pages you visit

    scripting

  • Store data in your browser

    storage

Updated 30 September 2026pdabfienifkbhoihedcgeogidfmibmhp