Is MathSolver safe?

Low risk

MathSolver is low risk. When signed in, MathSolver hashes your account email with SHA-256 and uses the digest as both the Analytics user ID and client ID. Sent to www.google-analytics.com/collect, making the hashed email a stable identifier across events.

Wizkids A/Sv3.0.24Chrome Web Store
19Risk

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

Publishers can request a review.

Findings

MathSolver hashes your email for Google Analytics

LowunwantedCWE-359Dynamic sandbox

When signed in, MathSolver hashes your account email with SHA-256 and uses the digest as both the Analytics user ID and client ID.

What actually happens

You did this

You use MathSolver while signed in and an analytics event is created.

Examples in the shipped code include login and math calculation events.

The extension did this

The extension hashes your account email address and sends that digest as two analytics identifiers.

If no session exists, the same code sends the literal value NO_SESSION instead of an email-derived hash.

Fields constructed for the Google Analytics request

  • Email-derived analytics identifier
    917390c4ca69759b77e6fa946f518cd9210bf84593e58ec7f42e017b1d96b1c9

    Tied to your account email; the same email makes the same hash, linking MathSolver events from that signed-in account over time.

  • Second copy of the same identifier
    917390c4ca69759b77e6fa946f518cd9210bf84593e58ec7f42e017b1d96b1c9

    Repeats the same email-derived value in a second field, so both analytics identifiers point to the same account hash.

  • Analytics property
    UA-79284543-25

    This routes the event to MathSolver's configured Google Analytics property.

  • Extension and version
    MathSolver 3.0.24

    This tells the analytics service which extension and version generated the event.

  • Event category and action
    Math / Calculate

    This describes what you did in the extension when the analytics event was created.

Captured request

POSThttps://www.google-analytics.com/collect

The shipped code posts a URL-encoded Google Analytics Measurement Protocol event to this endpoint.

The code that does this

The bundled analytics code hashes the email and posts it to Google Analytics

Readable version

Readable equivalent of the tracking configuration

background.js
class LingappsConfig {  constructor() {    this.baseUrl = "https://services.lingapps.dk";    this.application = "cas";    this.licenseName = "casLicense";    this.googleAnalyticsTrackingId = "UA-79284543-25";  }}

Readable equivalent of the analytics event definitions

background.js
const Events = {  SessionLoggedIn: () => new GoogleAnalyticsEvent("Session", "Logged in"),  MathCalculate: () => new GoogleAnalyticsEvent("Math", "Calculate"),  MathSolve: () => new GoogleAnalyticsEvent("Math", "Solve"),  MathParseGoogleLatex: () => new GoogleAnalyticsEvent("Math", "Parse Google Latex"),  MathLatexToImage: () => new GoogleAnalyticsEvent("Math", "Latex to image"),  UserClickTriangleCalculator: () => new GoogleAnalyticsEvent("User click", "Triangle calculator"),  UserClickInsertUnit: (value) => new GoogleAnalyticsEvent("User click", "Insert unit", value),  UserClickInsertSymbol: (value) => new GoogleAnalyticsEvent("User click", "Insert symbol", value)};

Readable equivalent of GoogleAnalyticsClient._send

background.js
class GoogleAnalyticsClient {  constructor(userService, config) {    this._userService = userService;    this._config = config;  }  async _send(category, action, label, value) {    const session = await this._userService.getSession();    const identifier = session      ? await async function hashEmail(email) {          const encoded = new TextEncoder().encode(email);          const digest = await crypto.subtle.digest("SHA-256", encoded);          return Array.from(new Uint8Array(digest))            .map(byte => byte.toString(16).padStart(2, "0"))            .join("");        }(session.user.email)      : "NO_SESSION";    const body = {      v: 1,      tid: this._config.googleAnalyticsTrackingId,      t: "event",      uid: identifier,      cid: identifier,      an: "MathSolver",      aid: chrome.runtime.id,      av: chrome.runtime.getManifest().version,      ec: category,      ea: action    };    if (label !== undefined) {      body.el = label;    }    if (value !== undefined) {      body.ev = value;    }    const encodedBody = Object.entries(body)      .map(([key, entryValue]) => encodeURIComponent(key) + "=" + encodeURIComponent(entryValue))      .join("&");    try {      await fetch("https://www.google-analytics.com/collect", {        method: "POST",        body: encodedBody      });    } catch (error) {    }  }  async send(event) {    await this._send(event.category, event.action, event.label, 1);  }}

Readable equivalent of math request analytics triggers

background.js
class GoogleAnalyticsMiddleware {  constructor(googleAnalyticsService) {    this._googleAnalyticsService = googleAnalyticsService;  }  async onRequest(request) {    if (request.url.includes("/cas/calculate")) {      this._googleAnalyticsService.send(Events.MathCalculate());    } else if (request.url.includes("/cas/solve")) {      this._googleAnalyticsService.send(Events.MathSolve());    } else if (request.url.includes("/cas/parseGLatex")) {      this._googleAnalyticsService.send(Events.MathParseGoogleLatex());    } else if (request.url.includes("/cas/latexToImage")) {      this._googleAnalyticsService.send(Events.MathLatexToImage());    }    return request;  }  async onResponse(response) {    return response;  }  async onError(error) {  }}

External host receiving the analytics identifier

    • www.google-analytics.com

    Receives the Measurement Protocol event containing the repeated SHA-256 hash of the signed-in account email, the MathSolver app name, extension version, and event category/action.

What it can do

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

    *://*.lingapps.dk/*

  • Read and change your data on wizkids.dk

    *://*.wizkids.dk/*

  • Read and change your data on accounts.google.com

    *://*.accounts.google.com/*

  • Read and change your data on docs.google.com

    *://*.docs.google.com/*

  • Read and change your data on login.microsoftonline.com

    *://login.microsoftonline.com/*

  • Read and change your data on sso.emu.dk

    *://sso.emu.dk/*

  • Read and change your data on atlas.uni-login.dk

    *://atlas.uni-login.dk/*

  • Read and change your data on broker.unilogin.dk

    *://broker.unilogin.dk/*

  • Watch every request your browser makes

    webRequest

  • Block and redirect the requests your browser makes

    declarativeNetRequest

  • Store data in your browser

    storage

Updated 2 November 2026mkiafkjhhcglgfmcogbbameineefdpcp