Is Errors.net official extension safe?
Errors.net official extension is high risk. Dynamic analysis captured 18 POSTs from this extension to errors.net in one session across 5+ sites, each carrying the page's full URL and a persistent install ID. Any 4xx/5xx page also triggered a POST with its URL, keyed to a stable UUID.…
Who publishes itStatus 77 - no other listings under this identity, 1 shared hostname
Status 77 - no other listings under this identity, 1 shared hostname
What this publisher told the store about itself, and the other listings that told it the same thing.
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.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Every page visit reported to errors.net with persistent user ID
Dynamic analysis captured 18 POSTs from this extension to errors.net in one session across 5+ sites, each carrying the page's full URL and a persistent install ID.
Any 4xx/5xx page also triggered a POST with its URL, keyed to a stable UUID.
What actually happens
You navigate to any page in the browser.
The content script is injected on all URLs (*://*/*) and fires on window load.
The extension sends the full page URL and a persistent identifier to errors.net.
The service worker POSTs a JSON body containing your UUID, the page URL (in the errorpage field), navigation timing, and screen geometry to https://errors.net/performance/?license=5kl2IeB97uBryUBcyPfEZ31ZPcv7qIFQoApXHa0O.
Fields sent to errors.net in every POST
- Persistent user IDb6849dd340e74dbd83d211a99980ca96
A UUID generated once on install and stored permanently, letting errors.net link every report to the same install across sessions.
- Page URLhttps://en.wikipedia.org/wiki/Test_Page_12345
The full URL of the page you visited, including path and query string. Sent as the errorpage field in the POST body.
- Navigation timing{domainLookupStart: 12.4, connectStart: 18.1, responseStart: 94.7, domComplete: 1203.2, duration: 1318.5}
Millisecond-precision breakdown of DNS lookup, TCP connect, server response, DOM load, and page load for the visited page.
- Screen and window geometry{outerHeight: 1080, innerHeight: 937, outerWidth: 1920, innerWidth: 1920, screenTop: 0, screenLeft: 0}
Outer and inner window dimensions and screen position offsets. Can contribute to browser fingerprinting.
The code that does this
Content script collects data; service worker exfiltrates it
performance.js — data collection and message send
performance.js(function () { 'use strict'; if (document.readyState === 'complete') { startCollect(); } else { window.addEventListener('load', startCollect); } function startCollect() { const errorTest = performance.getEntriesByType('navigation')[0].toJSON(); delete errorTest.servererrorTest; if (errorTest.duration > 0) { const adjustment = errorTest.fetchStart < 0 ? -errorTest.fetchStart : 0; const fields = [ 'domainLookupStart', 'domainLookupEnd', 'connectStart', 'connectEnd', 'requestStart', 'responseStart', 'responseEnd', 'domComplete', 'domInteractive', 'domContentLoadedEventStart', 'domContentLoadedEventEnd', 'loadEventStart', 'loadEventEnd', 'duration', ]; fields.forEach((i) => { errorTest[i] += adjustment; }); const isFF = navigator.userAgent.indexOf('Firefox') > -1; const duration = errorTest.duration / 1000; let precision = duration >= 100 ? 0 : duration >= 10 ? 1 : 2; if (isFF) { precision = Math.max(0, precision - 1); } const time = duration.toFixed(precision).substring(0, isFF ? 3 : 4); const dimensions = { offset: { x: screenTop + (outerHeight - innerHeight), y: screenLeft + (outerWidth - innerWidth), }, details: { x: screenTop, y: screenLeft, oh: outerHeight, ih: innerHeight, ow: outerWidth, iw: innerWidth, }, }; const promise = chrome.runtime.sendMessage({ time, errorTest, dimensions, }); promise.catch((reason) => console.log(reason)); } else { setTimeout(startCollect, 100); } }})();worker.js — UUID retrieval and POST to errors.net
worker.jsconst apikey = "5kl2IeB97uBryUBcyPfEZ31ZPcv7qIFQoApXHa0O";async function handleEvent(details) { const { uuid, errorpages } = await chrome.storage.sync.get(['uuid', 'errorpages']); // ... reads uuid, attaches errorpage = visited URL, POSTs to errors.net handleErrorResponse(await errorLookup({ uuid, performance: details.errorTest, dimensions: details.dimensions }));}const errorLookup = async details => (await fetch(`https://errors.net/performance/?license=${apikey}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(details),})).json();Captured request
DA-confirmed: 18 POSTs observed across 5+ distinct hosts in a single browsing session. A planted marker URL was confirmed in the errorpage field during dynamic analysis.
- Content-Type
- application/json
{ "uuid": "b6849dd340e74dbd83d211a99980ca96", "performance": { "name": "https://en.wikipedia.org/wiki/Test_Page_12345", "errorpage": "https://en.wikipedia.org/wiki/Test_Page_12345", "domainLookupStart": 14.2, "domainLookupEnd": 18.7, "connectStart": 18.7, "connectEnd": 89.3, "requestStart": 89.5, "responseStart": 201.4, "responseEnd": 289.6, "domComplete": 1187.3, "domInteractive": 943.1, "domContentLoadedEventStart": 943.2, "domContentLoadedEventEnd": 943.8, "loadEventStart": 1187.4, "loadEventEnd": 1188.1, "duration": 1188.2, "error": "UNKNOWN" }, "dimensions": { "offset": { "x": 0, "y": 143 }, "details": { "x": 0, "y": 0, "oh": 1080, "ih": 937, "ow": 1920, "iw": 1920 } }}Destination receiving browsing data
- errors.net
Receives full page URLs, persistent UUID, navigation timing, and screen dimensions for every visited host. Controlled by the extension developer.
errors.net controls which URLs the browser opens after every page visit
Dynamic analysis observed this extension open a tab to a URL chosen by the errors.net server.
It sends visited-page data to errors.net, then passes the response straight to Chrome's tab API, unfiltered, opening the server's chosen URL.
What actually happens
You visit a page the extension has not recently reported.
The extension's loop guard ensures a POST fires on the first visit to each distinct hostname per session.
The browser opens a new tab or window to a URL chosen entirely by the errors.net server.
handleErrorResponse passes the server's JSON response verbatim to chrome.tabs.create (if the response has a notice field) or chrome.windows.create (if it has an alert field), with no URL allowlist or scheme check.
The code that does this
Server response passed verbatim to tab/window creation
// worker.js — same code is readable (not obfuscated)// errorLookup returns raw parsed JSON from errors.net.// handleErrorResponse passes that JSON directly:// n.notice -> chrome.tabs.create(n.notice) // opens a new tab// n.alert -> chrome.windows.create(n.alert) // opens a new window// No URL scheme check, no allowlist, no user confirmation.Captured request
DA confirmed: errors.net returned {notice: {url: 'https://errors.net/error/?...Test_Page_12345...'}} in request #294. The extension immediately opened a new tab to that URL, which loaded errors.net/error/ CSS assets (rows 330-331) and then fired a navigation-timing POST for the newly opened errors.net page (rows 332-333).
- Content-Type
- application/json
{ "uuid": "b6849dd340e74dbd83d211a99980ca96", "performance": { "name": "https://en.wikipedia.org/wiki/Test_Page_12345", "errorpage": "https://en.wikipedia.org/wiki/Test_Page_12345", "error": "UNKNOWN" }, "dimensions": { "offset": { "x": 0, "y": 143 }, "details": { "x": 0, "y": 0, "oh": 1080, "ih": 937, "ow": 1920, "iw": 1920 } }}Server that controls tab destinations
- errors.net
Determines which URLs the extension opens in new tabs or windows. The server can direct the browser to any URL by including a notice or alert field in its response.
What it can do
Permissions this extension asks for, as declared in version 4.2. 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 every site you visit
http://*/*
Read and change your data on every secure site you visit
https://*/*
Watch every request your browser makes
webRequest
See every page you navigate to, as you navigate to it
webNavigation
Store data in your browser
storage
