Is Sensor Tower - Web Insights safe?
Sensor Tower - Web Insights is medium risk. Code analysis shows the extension uploads visited hostnames, paths, durations and referrers, plus stored query parameters, to webstats.st-panel-api.com every five minutes, keyed by an install ID and birth year.…
Strong link to a flagged operator: 2 of the 5 other listings from the same operator are rated high or critical for malicious behaviour. Flagged: StayFocusd (high), Luna Adblock (high).
Who publishes itSensor Tower, Inc. - 5 other listings from the same operator, 4 of them carrying a finding
Sensor Tower, Inc. - 5 other listings from the same operator, 4 of them carrying a finding
What this publisher told the store about itself, and the other listings that told it the same thing.
Same operator - 5 listings
Published under a different store account, but sharing the registered address, contact or declared legal entity this one gave the store.
Shared hosts - 2 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.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Web Insights uploads visited hostnames and paths to its API every 5 minutes
Code analysis shows the extension uploads visited hostnames, paths, durations and referrers, plus stored query parameters, to webstats.st-panel-api.com every five minutes, keyed by an install ID and birth year.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Static analysis
You browse sites with the extension installed.
Every five minutes the extension posts the visited hosts and paths to webstats.st-panel-api.com.
Page view upload request body
throw r?.error(`Missing required parameter 'installId'`, i), Error(`Missing required parameter 'installId'`) } let i = (0, bt.default)(navigator?.userAgent); await t(`/v1/page_views/upload`, { method: `POST`, retry: 0, body: { app_id: e.appId, install_id: e.installId, time_zone: Ke(), device_name: n(i.browser?.name), device_type: i.os.name, birth_year: e.birthYear, websites: e.websites, diff_private_websites: e.diffPrivateWebsites } }) }Upload interval configuration
getAppId: () => dn, dev: !1, uploadIntervalInMs: 3e5, pageViews: { lastUploadedAtStorageKey: `@webstats/page-views-last-uploaded-at-key`,- websites.host.pathnews.example.com /politics/story-123
Each visited hostname and path with its page views.
- page_views[].referrerhttps://www.google.com/
Where you came from for each visit.
- install_idb7e2c1f0-5a3d-4e8b-9c11-2f6d0a7e4b90
Persistent identifier for this install.
- birth_year1985
Birth year supplied by the user.
- device_typeWindows
Operating system name.
- webstats.st-panel-api.com
Receives page views, sessions and query parameters at /v1/page_views/upload, /v1/web/upload, /v1/query_params/upload.
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.
Remote-config finders read AI chat page text and upload it to the vendor API
Code analysis shows finders delivered by remote config run a query language on AI chat sites, and text from config-chosen elements is uploaded to webstats.st-panel-api.com as interactionDetails.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Static analysis
The remote config defines a finder or interaction selector for an AI chat site.
The extension reads matching page text and uploads it to webstats.st-panel-api.com.
Interaction collection by cardSelector
for (let e of g) r.add(e.id); let _ = []; n?.interactions && (Object.entries(n.interactions).forEach(([t, n]) => { n.forEach(n => { Array.from(document.querySelectorAll(n.cardSelector)).forEach(i => { let a = n.skipInteractionDetails ? `` : i.textContent || ``, o = `unknown`; if (n.appName) o = n.appName; else if (n.appNamePattern) { let e = new RegExp(n.appNamePattern), t = i.textContent?.match(e); t && t[1] && (o = t[1].trim()) } let s = rd(a), l = rd(c + t + s); r.has(l) || (_.push({ id: l, contentHash: s, timestamp: m,Interactions upload
} async function fe(e) { await t(`/v1/ai/interactions`, { method: `POST`, retry: 0, body: { app_id: e.appId, install_id: e.installId, interactions: e.interactions } })- interactionDetailsModel: GPT-4o
Text of elements matched by a config-supplied selector.
- install_idb7e2c1f0-5a3d-4e8b-9c11-2f6d0a7e4b90
Persistent identifier for this install.
- model / plangpt-4o / premium
Model name and subscription tier detected on the page.
- webstats.st-panel-api.com
Serves shared-web-config and receives /v1/ai/interactions, /v1/ai/analytics and /v1/ai/links.
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.
Ad-finder hooks fetch and XHR on every site and uploads crawl data to p.qljx.co
Code analysis shows an ad-finder script is injected on supported sites, patches fetch and XHR, applies server-delivered rules, and uploads compressed crawl data with user agent and extension ID to p.qljx.co.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Static analysis
You open a page with display ads.
The extension uploads ad crawl data with your browser, language and extension ID to p.qljx.co.
Crawl upload to p.qljx.co
var Oh = class { config; fetch; constructor(e) { this.config = e, this.fetch = Dh(e) } async upload(e) { if (!await this.config.isEnabled()) return; let t = this.prepareData(e); this.config.logger?.info(`Uploading data:`, t); let n = await this.fetch(this.config.crawlUploadUrl, { method: `POST`, body: bh.default.compressToUint8Array(JSON.stringify(t)), headers: { "Content-Type": `application/octet-stream` } }).then(e => this.config.logger?.info({ status: e.status })).catch(this.config.logger?.error); this.config.logger?.info(`Response:`, n) } prepareData(e) { return { ...e, PartnerVersion: R.runtime.getManifest().version, ExtensionId: R.runtime.id, ExtensionVersion: this.config.extensionVersion, AdFinderVersion: `5.0.0`, UserAgent: navigator.userAgent,Upload and config endpoints
extensionVersion: p.runtime.getManifest().version, extensionId: dn, crawlUploadUrl: `https://p.qljx.co/Ajax0001/IPD`, pmExternalConfigUrl: `https://p.qljx.co/Ajax0001/Config`, panelPartnerId: 0- ExtensionIdnebpklfkdokhobloogjbbgajhddfjcbk
Identifies the installed extension.
- UserAgentMozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/124.0.0.0
Your browser and OS string.
- BrowserLanguageen-US
Your browser language.
- crawlUrlhttps://news.example.com/article
Page where the ad was found.
- p.qljx.co
Serves rules at /Ajax0001/Config and receives crawl uploads at /Ajax0001/IPD.
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.