Is MathSolver safe?
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.
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
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.
What actually happens
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 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 identifier917390c4ca69759b77e6fa946f518cd9210bf84593e58ec7f42e017b1d96b1c9
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 identifier917390c4ca69759b77e6fa946f518cd9210bf84593e58ec7f42e017b1d96b1c9
Repeats the same email-derived value in a second field, so both analytics identifiers point to the same account hash.
- Analytics propertyUA-79284543-25
This routes the event to MathSolver's configured Google Analytics property.
- Extension and versionMathSolver 3.0.24
This tells the analytics service which extension and version generated the event.
- Event category and actionMath / Calculate
This describes what you did in the extension when the analytics event was created.
Captured request
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 equivalent of the tracking configuration
background.jsclass 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.jsconst 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.jsclass 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.jsclass 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
