Is WOT: Website Security & Safety Checker safe?

Medium risk

This extension shows website safety ratings and warns about suspicious or harmful sites.

It provides real-time safety ratings while you browse, shop, and search, and can warn about suspicious or harmful links in emails. It also offers password data-breach monitoring, adult content blocking, safe shopping alerts, and community site reviews. The store description says WOT collects browsing data to enable real-time protection and website reputation features.

WOT Services Oyv5.9.2Chrome Web Store
48Risk
Who publishes it

WOT Services Oy - no other listings under this identity, 10 shared hostnames

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

Publisher
WOT Services Oy

Shared hosts - 10 hostnames

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.

analytics.api.mywot.com
Also called by 2 other listings, including Web of Trust, MyWOT/WOT: Website Reputation Rating
app.mywot.com
Also called by 2 other listings, including Web of Trust, MyWOT/WOT: Website Reputation Rating
leak.api.mywot.com
Also called by 2 other listings
secure.mywot.com
Also called by 2 other listings, including Web of Trust, MyWOT/WOT: Website Reputation Rating
support.mywot.com
Also called by 2 other listings, including Web of Trust, MyWOT/WOT: Website Reputation Rating
user.api.mywot.com
Also called by 2 other listings
auth.api.mywot.com
Also called by 3 other listings
scorecard.api.mywot.com
Also called by 3 other listings
static.mywot.com
Also called by 3 other listings
wotsurveys.typeform.com
Also called by 3 other listings

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

Publishers can request a review.

Findings

WOT sends analytics identifiers during extension events

WOT installs, updates, or remote-config changes trigger analytics records with a UUID, version, locale, and premium state, POSTed to WOT's event and UUID-sync endpoints.

A separate `/reportClientData` endpoint exists but wasn't observed.

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

You install, update, or activate WOT in the browser.

A remote configuration update can also trigger the user-data analytics path.

The extension did this

The extension sends analytics records tied to a persistent UUID to WOT-operated endpoints.

The code also prepares a remote-configuration-driven report that can include selected extension state fields.

Captured request
POSThttps://analytics.api.mywot.com/event

Observed during dynamic analysis: the POST body was 1,949 bytes and carried an encoded analytics event value.

Captured request
POSThttps://app.mywot.com/api/analytics/sync

Observed during dynamic analysis: the extension posted the persistent installation UUID to WOT's web app sync endpoint.

Headers
Content-Type
application/json
Body
{  "uuid": "b2e47d55-1e74-4f40-a49d-01c524552770"}
Fields tied to analytics events and UUID sync
  • Persistent installation UUID
    b2e47d55-1e74-4f40-a49d-01c524552770

    Lets WOT link analytics activity from the same browser profile across sessions.

  • Event type
    EXTENSION_INSTALL

    Shows which extension event or configured report caused the analytics record.

  • Extension version
    5.9.6

    Connects the analytics record to the exact WOT build running in your browser.

  • Locale and client context
    Chrome 124 on Windows, en-US

    Adds language, browser, operating-system, and user-agent context to the event.

  • Premium and opt-in state
    Tier: Free; is_premium: false; is_opt_in: true

    Shows whether your extension profile is treated as paid, trialing, or opted in for protection features.

  • Configured state fields
    user, settings, version

    A server-provided configuration can choose state fields from the extension store and include their current values in a report.

The code that does this

Extension code that builds and sends the analytics records

Readable version

Install/update events create an analytics payload

deobfuscated/scripts/background/index.js
webextApi.runtime.onInstalled.addListener(e => {  const t = "install" === e.reason,    s = "update" === e.reason;  initApp(s, t);  const a = webextApi.runtime.getManifest().version,    n = {      os: -1 !== navigator.userAgent.indexOf("Mac") ? "mac" : -1 !== navigator.userAgent.indexOf("win") ? "windows" : "",      eventSpecificFields: {        version_number: a,        full_user_agent: navigator.userAgent      }    };  t ? WotApi.sendAnalyticsFromBackground(ANALYTICS.ANALYTICS_EVENT_TYPES.EXTENSION_INSTALL, "", "", n) : s && WotApi.sendAnalyticsFromBackground(ANALYTICS.ANALYTICS_EVENT_TYPES.EXTENSION_UPGRADE, "", "", n)}), setTimeout(() => {  initApp(!1, !1)}, 500);

WotApi posts events and user-data reports

deobfuscated/scripts/shared/wotApi.js
sendAnalyticsFromBackground(t, e, s, r) {  const i = {    [GA_ACTION_KEY]: t || "",    [GA_LABEL_KEY]: e || "",    testGroup: s,    eventPayload: r  };  this.sendInternalAnalytics(i)}async sendInternalAnalytics(t) {  try {    const e = t[GA_ACTION_KEY],      s = t[GA_LABEL_KEY],      r = t.testGroup,      i = t.eventPayload,      n = await this.getOrInitAnalyticsInfoFromLocalStorage(),      o = new WotAnalyticsEvent(e, s, r, i, n);    await o.loadStateFields();    const a = this.methods.analytics.url;    this.postJson(a, o.createPayload()).catch(t => {})  } catch (t) {}}sendUserDataAnalytics(t, e, s, r) {  try {    const i = new UserDataAnalyticsEvent(t, e, s, r);    this.postJson(this.methods.userDataAnalytics.url, i.createPayload(), headers).catch(t => {})  } catch (t) {}}

Analytics event classes encode the event body

deobfuscated/scripts/shared/utils.js
class AnalyticsEvent {  createPayload() {    return {      ev: btoa(Array.from(JSON.stringify(this)).map((e, t) => e.charCodeAt(0) - (this.uuid.length + 2 * t)).toString()),      se: this.uuid    }  }}class WotAnalyticsEvent extends AnalyticsEvent {  constructor(e, t, n, o, i) {    super(), this.product = ANALYTICS.ANALYTICS_PRODUCT, this.platform = ANALYTICS.ANALYTICS_PLATFORM, this.uuid = i, this.timestamp = Date.now(), this.resource = ANALYTICS.ANALYTICS_RESOURCE_TYPES.ORGANIC, this.country = getLocale(), this.user_agent = browserName, this.event_type = e, this.purchase_source = t, this.test_group = n, this.payload = o || {}, this.payload.extension_version = VERSION  }  async loadStateFields() {    const e = await getExtensionState();    let t = !1,      n = !1;    e && (e.user && e.user.isPremiumUser && (t = e.user.isPremiumUser), e.settings && e.settings.protection && (n = e.settings.protection)), this.payload.is_premium = t, this.payload.is_opt_in = n  }}class UserDataAnalyticsEvent extends AnalyticsEvent {  constructor(e, t, n, o) {    super(), this.product = "WOT", this.platform = "extension", this.uuid = WOT_TRACE_ID.value.slice(3), this.timestamp = Date.now(), this.country = getLocale(), this.eventMessage = e, this.versionNumber = t, this.isPremiumUser = n, this.userState = o  }}

Remote configuration selects state fields for /reportClientData

deobfuscated/scripts/background/app/aliases.js
[HANDLE_USER_DATA_ANALYTICS]: e => (t, a) => {  try {    const t = e.data.forUpdate[USER_DATA_ANALYTICS];    if (t) {      const e = a(),        s = e.remoteConfig.features[USER_DATA_ANALYTICS];      if (Date.now() > t.endDate || s && s.version === t.version) return;      const r = t.eventName,        i = t.stateFields,        n = VERSION,        o = e.user,        d = !!o && o.isPremiumUser,        A = {};      i.forEach(t => {        A[t] = e[t]      }), WotApi.sendUserDataAnalytics(r, n, d, A)    }  } catch (e) {}}

UUID sync posts a JSON body to the web app endpoint

deobfuscated/scripts/shared/wotApi.js
async syncAnalyticInfoWithWebapp() {  let t, e;  try {    const s = await fetch(ANALYTIC_INFO);    200 === s.status && (t = await s.json()), e = t && t.uuid || generateUuidV4(), await fetch(ANALYTIC_INFO, {      method: "POST",      headers: {        "Content-Type": "application/json"      },      body: JSON.stringify({        uuid: e      })    })  } catch (t) {}  return e}
The code that does this

Additional Mixpanel tracking path in the extension source

Readable version
var _extends = Object.assign || function(e) {  for (var r = 1; r < arguments.length; r++) {    var t = arguments[r];    for (var s in t) Object.prototype.hasOwnProperty.call(t, s) && (e[s] = t[s])  }  return e};class Mixpanel {  constructor(e) {    this.store = e, this.mixpanel = mixpanel.init("9c2a5bc5df124e35970da2299c103485")  }  getSuperProperties(e) {    const r = e.user || {},      t = new UAParser(navigator.userAgent),      s = t.getOS().name;    return {      $browser: t.getBrowser().name,      $browser_version: t.getBrowser().version.split(".")[0],      $os: `${s}${"Mac OS"===s?" X":""}`,      Platform: "Web",      platform_source: "extension",      "Is Logged In": !!r.mail,      Tier: r.isPremiumUser ? "Premium" : "Free",      $app_version_string: e.version.versionNumber,      "Had Trial": !(!r.isPremiumUser && !r.isTrialing)    }  }  flushQueue(e, r, t) {    e && (t.forEach(t => {      this.track(t.eventType, t.properties, e, r)    }), this.store.dispatch(deleteMixpanelQueue()))  }  send(e) {    const r = e.eventType;    var t = e.properties;    const s = void 0 === t ? {} : t,      i = this.store.getState();    if (!i.isAutomation) {      const e = _extends({}, this.getSuperProperties(i), s),        t = i.mixpanel.distinctId;      if (t) {        const s = i.userIp;        this.track(r, e, t, s)      } else this.store.dispatch(addMixpanelEventToQueue({        eventType: r,        properties: e      }))    }  }  track(e, r, t, s) {    this.mixpanel.track(e, _extends({}, r, {      distinct_id: t,      ip: s    }))  }}
Reproduce it yourself

Decodes a captured WOT analytics `/event` JSON body so you can inspect the encoded event fields.

Requires
  • Node.js 18+
wot-analytics-decode.js · js
#!/usr/bin/env nodeconst fs = require('fs');const input = fs.readFileSync(0, 'utf8').trim();if (!input) {  console.error('Usage: node wot-analytics-decode.js < captured-event-body.json');  process.exit(1);}const payload = JSON.parse(input);if (typeof payload.ev !== 'string' || typeof payload.se !== 'string') {  throw new Error('Expected JSON with string fields ev and se');}const csv = Buffer.from(payload.ev, 'base64').toString('utf8');const numbers = csv.split(',').map((value) => {  const parsed = Number(value);  if (!Number.isFinite(parsed)) {    throw new Error(`Invalid encoded value: ${value}`);  }  return parsed;});const decoded = numbers  .map((value, index) => String.fromCharCode(value + payload.se.length + 2 * index))  .join('');console.log(JSON.stringify(JSON.parse(decoded), null, 2));
How to run it
  1. 1node wot-analytics-decode.js < captured-event-body.json
Hosts shown by traffic evidence and compiled source
    • analytics.api.mywot.com

    WOT analytics host; dynamic analysis observed a POST to `/event`, and source code also defines `/reportClientData`.

    • app.mywot.com

    WOT web app host; dynamic analysis observed the extension POSTing its persistent UUID to `/api/analytics/sync`.

    • api.mixpanel.com

    Mixpanel analytics host compiled into the extension bundle; the WOT wrapper adds browser, OS, tier, distinct ID, and IP fields when it sends Mixpanel events.

What it can do

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

  • Read and change your data on www.mywot.com

    http://www.mywot.com/*

  • Read and change your data on api.mywot.com

    http://api.mywot.com/* and 1 more

  • Read and change your data on every site you visit

    http://*/*

  • Read and change your data on every secure site you visit

    https://*/*

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

    tabs

  • Add items to the right-click menu

    contextMenus

  • See every page you navigate to, as you navigate to it

    webNavigation

  • Watch every request your browser makes

    webRequest

  • 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

  • Run its own code inside the pages you visit

    scripting

  • Schedule its own background tasks

    alarms

Where it sends data

Destinations our analysis observed Web of Trust contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.

  • WOT

    Web of Trust sends data to WOT. Named as a recipient in this extension's own analysis.

Updated 30 September 2026bhmmomiinigofkjcapegjjndpbikblnp