Is VPN safe?

Medium risk

VPN sends the full URL and HTTP referrer of every page visited to api.sandvpn.com along with a persistent user identifier.

On every browser navigation, the extension captures the visited URL, the page's HTTP referrer, and a persistent random userId stored in sync storage, then transmits them to api.sandvpn.com/smartProxy. During sign-in the extension forwards the raw Google OAuth access_token to api.sandvpn.com/google before exchanging it for a service token. All browser traffic is routed through HTTP (not HTTPS) proxy servers whose credentials are fetched from api.sandvpn.com and stored in plaintext in sync storage.

SandVPNv9.7.2Firefox Add-ons
50Risk

AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.

Publishers can request a review.

Findings

Google OAuth token sent to SandVPN backend

MediumunwantedCWE-200Dynamic sandbox

Clicking Google sign-in starts an OAuth flow for openid, email, and profile.

What actually happens

You did this

You click the Google sign-in button in the VPN extension.

The popup sends a googleOauth message to the background script.

The extension did this

The extension extracts the Google OAuth access token and posts it to SandVPN's backend.

The request goes to https://api.sandvpn.com/google immediately after the OAuth redirect is handled.

Captured request

POSThttps://api.sandvpn.com/google
Headers
Content-Type
application/json
Access-Control-Allow-Origin
*

Data sent in the sign-in request

  • Google OAuth access token
    access_token=<redacted>

    This token represents the Google sign-in access granted to the extension for the requested profile scopes.

  • Requested Google profile access
    openid email profile

    This lets the sign-in flow identify your Google account profile and email address to the service.

The code that does this

Popup click, OAuth redirect parsing, and backend POST

Readable version

Popup Google sign-in click handler

main.js
onClick: function() {  p(!0), browser.runtime.sendMessage({    action: "googleOauth"  })}

Background POST helper

background.js
function f(e) {  return p.apply(this, arguments)}function p() {  return (p = l(c().mark((function e(t) {    return c().wrap((function(e) {      for (;;) switch (e.prev = e.next) {        case 0:          return e.abrupt("return", fetch("https://api.sandvpn.com/google", {            method: "POST",            headers: {              "Content-Type": "application/json",              "Access-Control-Allow-Origin": "*"            },            body: JSON.stringify(t)          }).then((function(e) {            if (!e.ok) {              if (500 === e.status) throw new Error("Server Error");              return e.text().then((function(e) {                throw e              }))            }            return e.json()          })));        case 1:        case "end":          return e.stop()      }    }), e)  })))).apply(this, arguments)}

Redirect parser and Google OAuth launcher

background.js
function x(e) {  return k.apply(this, arguments)}function k() {  return (k = l(c().mark((function e(t) {    var r, n, o, a, s, u, l;    return c().wrap((function(e) {      for (;;) switch (e.prev = e.next) {        case 0:          if (r = t.match(/access_token=(.*?)&/i)[1], n = browser.extension.getViews({              type: "popup"            }), !r) {            e.next = 27;            break          }        return e.prev = 3, o = {          access_token: r        }, e.next = 7, f(o);        case 7:          return a = e.sent, e.next = 10, w(a.token);        case 10:          if (null == (s = e.sent) || !s.premium) {            e.next = 16;            break          }          return e.next = 14, v(a.token);        case 14:          u = e.sent, browser.storage.sync.set({            proxyInfos: u          });        case 16:          l = i(i(i({}, a), s), {}, {            isAuth: !0          }), browser.storage.sync.set({            userInfo: l          }), n.length || m({            path: "user"          }), e.next = 26;          break;        case 23:          e.prev = 23, e.t0 = e.catch(3), console.log(e.t0);        case 26:        case 27:        case 28:        case "end":          return e.stop()      }    }), e, null, [      [3, 23]    ])  })))).apply(this, arguments)}function L() {  return (e = browser.identity.getRedirectURL(), t = "https://accounts.google.com/o/oauth2/auth", t += "?client_id=".concat("368215438305-s6n3g9q6roovov01p03b5kgm8f248cpr.apps.googleusercontent.com"), t += "&prompt=select_account", t += "&response_type=token", t += "&redirect_uri=".concat(encodeURIComponent(e)), t += "&scope=".concat(encodeURIComponent(["openid", "email", "profile"].join(" "))), browser.identity.launchWebAuthFlow({    interactive: !0,    url: t  })).then(x);  var e, t}

External services involved in this sign-in path

    • accounts.google.com

    Google OAuth consent and redirect endpoint for the openid, email, and profile scopes.

    • api.sandvpn.com

    SandVPN backend that receives the Google OAuth access token and returns a SandVPN service token.

What it can do

Permissions this extension asks for, as declared in version 9.7.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

    <all_urls>

  • Sign you in with your Google account

    identity

  • See every page you navigate to, as you navigate to it

    webNavigation

  • Read and change cookies, including the ones that keep you signed in

    cookies

  • Clear your browsing history, cache and cookies

    browsingData

  • Show you desktop notifications

    notifications

  • See the address and title of every tab you have open

    tabs

  • Change your browser's privacy and security settings

    privacy

  • Route all of your browsing through a server of its choosing

    proxy

  • See, disable and uninstall your other extensions, including your security ones

    management

  • Store data in your browser

    storage

  • Watch every request your browser makes

    webRequest

  • Watch, block and rewrite every request your browser makes

    webRequestBlocking

  • Act on the current tab, but only after you click the extension

    activeTab

  • Add items to the right-click menu

    contextMenus

  • Write to your clipboard

    clipboardWrite

  • Schedule its own background tasks

    alarms

contextualIdentities

Where it sends data

Destinations our analysis observed VPN contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.

  • api.sandvpn.com

    VPN sends data to api.sandvpn.com. One other extension we have analyzed sends data here.

Updated 2 November 2026amo-2748136