Is Videochat Extension - IP Locator for Omegle safe?
Videochat IP Locator is medium risk. Uninstalling triggers Chrome to visit a URL encoding a profile: time installed, browser language, Patreon status, and a timezone flag for outside Russia/CIS. XOR-encoded with a hardcoded key, trivially readable by an interceptor.…
Who publishes itqrluke - no other listings under this identity, 1 shared hostname
qrluke - 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
Install profile sent to developer server when you uninstall
Uninstalling triggers Chrome to visit a URL encoding a profile: time installed, browser language, Patreon status, and a timezone flag for outside Russia/CIS.
XOR-encoded with a hardcoded key, trivially readable by an interceptor.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Dynamic sandbox
You uninstall the extension from your browser.
Chrome fetches a pre-registered URL encoding an install profile, including a flag for whether your clock is set to a Russian or CIS timezone.
The profile is XOR-encoded with a static hardcoded key visible in the extension source, making it readable by anyone who intercepts the request.
- First seen timestamp1748000000000
When the extension was first installed on your browser.
- Legacy user flagfalse
Whether your install predates the current version series.
- First install flagfalse
Whether this was your very first install of the extension.
- Legacy stats time0
Accumulated usage time recorded under an older storage format.
- Outside CIS timezonetrue
True if your timezone is not one of 27 Russian/CIS zones in the source, letting the developer infer your approximate region.
- Patreon statusunknown
Whether you were expected to have an active Patreon subscription.
- Browser languageen
Your browser's reported UI language.
Profile assembly and XOR encoding (background.js:1619-1642)
Profile assembly and uninstall URL registration
background.jsasync function buildAndRegisterUninstallUrl() { const { legacy } = await chrome.storage.sync.get({ legacy: { stats: { time: 0 } } }); const legacyTime = legacy?.stats?.time || 0; const profile = { fs: await getStorage('firstSeen', 0), // first seen timestamp ilu: await getStorage('isLegacyUser', false), // is legacy user fi: await getStorage('firstInstall', false), // first install ots: legacyTime, // old stats time pa: !CIS_TIMEZONES.includes( // NOT in Russian/CIS timezone Intl.DateTimeFormat().resolvedOptions().timeZone), pstba: await getStorage('patreonSupposedToBeActive', 'unknown'), lg: chrome.i18n.getMessage('language'), // browser language }; function xorEncode(str, key) { let out = ''; for (let i = 0; i < str.length; i++) out += String.fromCharCode(str.charCodeAt(i) ^ key.charCodeAt(i % key.length)); return out; } const encoded = btoa( xorEncode(JSON.stringify(profile), 'a-super-secret-key-that-is-not-so-secret') ); const url = `https://api.vext.works/farewell?v=${chrome.runtime.getManifest().version}&data=${encodeURIComponent(encoded)}`; chrome.runtime.setUninstallURL(url);}The profile is XOR-encoded with a static key visible in the source code, then base64-encoded. The result is placed in the data= query parameter of the uninstall URL. Anyone with the key (published here) can decode any captured uninstall request.
{ "fs": 1780680743225, "ilu": false, "fi": false, "ots": 0, "pa": true, "pstba": "unknown", "lg": "en"}Decodes any uninstall URL data= parameter captured from this extension, producing the original profile JSON.
- Node.js 14+
#!/usr/bin/env node// Decode the data= parameter from api.vext.works/farewell uninstall requests.// Source: background.js:1637-1641 (XOR key hardcoded at line 1639)const KEY = 'a-super-secret-key-that-is-not-so-secret';function xorDecode(encoded, key) { let result = ''; for (let i = 0; i < encoded.length; i++) result += String.fromCharCode(encoded.charCodeAt(i) ^ key.charCodeAt(i % key.length)); return result;}// Pass the raw value of the data= query parameter (URL-decoded) as the first argument.const b64 = decodeURIComponent(process.argv[2] || '');if (!b64) { console.error('Usage: node decode-uninstall-payload.js <base64_data_param>'); console.error('Example: node decode-uninstall-payload.js Gg8VBlJfQxpDVVNCVUQdW1VJHVhKCBhYS0lLDwMHSF9NSxpHWRQEGBJIX1cfEQEPSVVPUBUVD1ERC1gRREMEXh0RTExVVlgdBEMcEg1QSVYNSlFPUgAcDw4%3D'); process.exit(1);}const decoded = Buffer.from(b64, 'base64').toString('binary');const plaintext = xorDecode(decoded, KEY);console.log('Decoded profile:');try { const parsed = JSON.parse(plaintext); console.log(JSON.stringify(parsed, null, 2)); console.log(); console.log('Field meanings:'); console.log(' fs =', parsed.fs, ' (firstSeen timestamp, ms since epoch)'); console.log(' ilu =', parsed.ilu, ' (isLegacyUser)'); console.log(' fi =', parsed.fi, ' (firstInstall)'); console.log(' ots =', parsed.ots, ' (legacy stats time)'); console.log(' pa =', parsed.pa, ' (true = NOT in Russian/CIS timezone)'); console.log(' pstba=', parsed.pstba,' (patreonSupposedToBeActive)'); console.log(' lg =', parsed.lg, ' (browser language)');} catch(e) { console.log('Raw plaintext:', plaintext);}- 1Capture the GET request to https://api.vext.works/farewell when uninstalling the extension.
- 2Copy the value of the data= query parameter.
- 3Run: node decode-uninstall-payload.js '<data_value>'
Behavior config fetched from third-party JSON hosts at startup
Each browser start, the extension fetches its config from up to four URLs, two public JSON hosts (jsonsilo.com, npoint.io) anyone can register on.
The payload is encrypted with a hardcoded passphrase and RSA-signed.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-829
- Source
- Dynamic sandbox
You install the extension or restart your browser.
The extension fetches its config from a priority-ordered list of four URLs, two of which are on third-party public JSON hosting services.
The decrypted config controls which sites the extension activates on and can override the redirect URL shown when a blocked site is visited.
- vext.works
Primary config endpoint, developer-controlled domain.
- api.jsonsilo.com
First fallback, public third-party JSON hosting. Specific bucket UUID 3f0366b1-ddea-467f-83d8-cc8ba36c4cab hardcoded in source.
- api.npoint.io
Second fallback, public third-party JSON hosting. Specific document ID df41cdd27f701e150e23 hardcoded in source.
- api.vext.works
Third fallback, developer-controlled subdomain.
Priority fetch loop and endpoint list (background.js:749, 764-795)
Endpoint list
background.jsconst CONFIG_URLS = [ "https://vext.works/status.json", "https://api.jsonsilo.com/public/3f0366b1-ddea-467f-83d8-cc8ba36c4cab", "https://api.npoint.io/df41cdd27f701e150e23", "https://api.vext.works/status.json"];Fetch loop
background.jsasync function fetchRemoteConfig(timeoutMs = 5000) { for (let i = 0; i < CONFIG_URLS.length; i++) { const url = CONFIG_URLS[i]; try { const response = await fetchWithTimeout(url, timeoutMs); if (!response.ok) continue; let data = await response.json(); if (typeof data === 'string') { try { data = JSON.parse(data); } catch { continue; } } if (!isValidConfigShape(data)) continue; const decrypted = await decryptAndVerify(data); if (!decrypted) continue; if (!isValidConfigContent(decrypted)) continue; await chrome.storage.local.set({ encryptedDataCache: data }); return decrypted; } catch { continue; } } return null;}Once decrypted and validated, the config's `blacklist` array is merged with the extension's built-in site list to determine which videochat sites the extension activates on. A `forgivelist` array can remove sites from that combined list. The `try_this_instead` or `try_this_instead_dict` field supplies a redirect URL that the extension displays when a user navigates to a blacklisted site. DA observed the extension making this fetch 6 times during a 120-second session observed during dynamic analysis, all returning HTTP 200.
What it can do
Permissions this extension asks for, as declared in version 4.1.7. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Act on the current tab, but only after you click the extension
activeTab
Add items to the right-click menu
contextMenus
Show a panel beside the page
sidePanel
Store data in your browser
storage
See the address and title of every tab you have open
tabs
Speak text aloud
tts
Store an unlimited amount of data in your browser
unlimitedStorage