Is VMP™ Pass Password Manager safe?

High risk

VMP Pass is high risk. When you verify or set the vault master password, the extension builds a JSON request with your email and typed password, sent to passwordmanager.themebeaver.com:5443. Not reached live; test account was unregistered. Evidenced from source.…

VPN Master Prov3.2.1Chrome Web Store
79Risk
Who publishes it

VPN Master Pro - no other listings under this identity

What this publisher told the store about itself, and the other listings that told it the same thing.

Publisher
VPN Master Pro

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

Publishers can request a review.

Findings

Master password posted to Themebeaver API

When you verify or set the vault master password, the extension builds a JSON request with your email and typed password, sent to passwordmanager.themebeaver.com:5443.

Not reached live; test account was unregistered.

Evidenced from source.

Severity
High unwanted
Type
Unexpected
CWE
CWE-522
Source
Dynamic sandbox
What actually happens
You did this

You enter the vault master password during verification or setup.

The extension did this

The extension places that password in a JSON request to the Themebeaver API.

Fields built into the password request
  • Account email
    user@example.com (illustrative)

    This ties the password check to your password-manager account.

  • Vault master password
    correct-horse-battery-staple (illustrative)

    This is the password you rely on to unlock or create the vault.

Captured request
POSThttps://passwordmanager.themebeaver.com:5443/api/verify-password
Headers
Content-Type
application/json
The code that does this

Verification and setup handlers build password JSON requests

Readable version

Readable verify-password handler

assets/masterPass.js
d0 = B("master_password", "verify_password", async t => {  if (t.preventDefault(), !E) {    const r = new Error("Please enter your master password");    v("master_password", "validation", r, {      hasPassword: !1,      passwordLength: 0    }), n(r.message);    return  }  d(!0), n("");  try {    const s = await (await q(`${g}/api/verify-password`, {      method: "POST",      headers: {        "Content-Type": "application/json"      },      body: JSON.stringify({        email: e,        password: E      }),      context: {        component: "MasterPass",        action: "verifyPassword",        userEmail: e      }    })).json();    if (s.success && s.verified) {      try {        const i = await (await fetch(`${g}/api/salt/${encodeURIComponent(S)}`)).json();        if (!i.success || !i.salt) throw new Error("Failed to retrieve encryption salt");        const x = await N.deriveEncryptionKey(E, i.salt);        await N.storeEncryptionKey(x, S)      } catch (o) {        console.error("❌ Failed to generate encryption key:", o), n("Failed to setup encryption. Please try again."), d(!1);        return      }      try {        await Q(e)      } catch (o) {        console.error("⚠️ Failed to load settings, will use defaults:", o)      }      chrome.storage.local.get(["userSettings"], o => {        if (console.log("🔍 [MasterPass-Verify] Checking userSettings:", o.userSettings ? "EXISTS" : "NOT FOUND"), o.userSettings) console.log("⏭️ [MasterPass-Verify] Settings already exist, skipping initialization");        else {          console.log("🆕 [MasterPass-Verify] Initializing default settings...");          const i = {            accessibility: !1,            biometricLogin: !1,            passwordSuggestions: !0,            matchSubdomain: !1,            autoSubmit: !1,            vmpfillTool: !0,            autofillPrompt: !0,            savePasswordPrompt: !0,            changePasswordPrompt: !0,            httpWarningPrompt: !0,            vmpfillDisabledPrompt: !0,            clipboard: {              enabled: !0,              time: "30"            },            security: {              stayLoggedIn: !0,              inactivityTimer: {                value: "30",                unit: "Minutes"              }            },            fieldIcons: "always",            theme: "Light",            promptLocation: {              location: "Top Right",              animation: "Slide In"            }          };          chrome.storage.local.set({            userSettings: i          }, () => {            chrome.runtime.lastError ? console.error("❌ [MasterPass-Verify] Error storing settings:", chrome.runtime.lastError) : console.log("✅ [MasterPass-Verify] Default settings initialized successfully")          })        }      }), chrome.storage.local.set({        vault_unlocked: !0,        vault_unlock_time: new Date().getTime()      }, async () => {        const o = chrome.runtime.lastError;        if (o) {          console.error("Storage error:", o), n("Failed to unlock vault. Please try again."), d(!1);          return        }        if (K(), await J("master_password", e, e == null ? void 0 : e.split("@")[0], "vault_unlock"), L) {          window.close();          return        }        try {          (await chrome.windows.getCurrent()).type === "popup" ? window.close() : F()        } catch {          F()        }      })    } else if (s.passwordNotSet || s.error === "Password not set for this user") p("set"), H("");    else {      const o = new Error("Invalid master password");      v("master_password", "authentication_failed", o, {        passwordNotSet: s.passwordNotSet,        apiError: s.error,        verified: s.verified      }), n(o.message)    }  } catch (r) {    const s = new Error("An error occurred. Please try again.");    v("master_password", "network_error", r, {      originalMessage: r.message,      userEmail: e    }), n(s.message)  } finally {    d(!1)  }})

Readable update-password handler

assets/masterPass.js
h0 = async () => {  U(!1), _("masterpass_warning_confirmed", {    user_email: e,    timestamp: new Date().toISOString()  }), C("masterpass_warning_confirmed", {    user_email: e,    timestamp: new Date().toISOString()  }), d(!0), n("");  try {    const r = await (await q(`${g}/api/update-password`, {      method: "PUT",      headers: {        "Content-Type": "application/json"      },      body: JSON.stringify({        email: e,        password: w      }),      context: {        component: "MasterPass",        action: "setPassword",        userEmail: e      }    })).json();    if (r.success) {      try {        const o = await (await fetch(`${g}/api/salt/${encodeURIComponent(S)}`)).json();        if (!o.success || !o.salt) throw new Error("Failed to retrieve encryption salt");        const i = await N.deriveEncryptionKey(w, o.salt);        await N.storeEncryptionKey(i, S)      } catch (s) {        console.error("❌ Failed to generate encryption key:", s), n("Failed to setup encryption. Please try again."), d(!1);        return      }      chrome.storage.local.get(["userSettings"], s => {        if (console.log("🔍 [MasterPass] Checking userSettings:", s.userSettings ? "EXISTS" : "NOT FOUND"), s.userSettings) console.log("⏭️ [MasterPass] Settings already exist, skipping initialization");        else {          console.log("🆕 [MasterPass] Initializing default settings...");          const o = {            accessibility: !1,            biometricLogin: !1,            passwordSuggestions: !0,            matchSubdomain: !1,            autoSubmit: !1,            vmpfillTool: !0,            autofillPrompt: !0,            savePasswordPrompt: !0,            changePasswordPrompt: !0,            httpWarningPrompt: !0,            vmpfillDisabledPrompt: !0,            clipboard: {              enabled: !0,              time: "30"            },            security: {              stayLoggedIn: !0,              inactivityTimer: {                value: "30",                unit: "Minutes"              }            },            fieldIcons: "always",            theme: "Light",            promptLocation: {              location: "Top Right",              animation: "Slide In"            }          };          chrome.storage.local.set({            userSettings: o          }, () => {            chrome.runtime.lastError ? console.error("❌ [MasterPass] Error storing settings:", chrome.runtime.lastError) : console.log("✅ [MasterPass] Default settings initialized successfully")          })        }      }), chrome.storage.local.set({        vault_unlocked: !0,        vault_unlock_time: new Date().getTime()      }, async () => {        const s = chrome.runtime.lastError;        if (s) {          console.error("Storage error:", s), n("Failed to save vault state. Please try again."), d(!1);          return        }        _("masterpass_password_created", {          user_email: e,          timestamp: new Date().toISOString()        }), await C("masterpass_password_created", {          user_email: e,          timestamp: new Date().toISOString()        }), await K(), await J("master_password", e, e == null ? void 0 : e.split("@")[0], "new_account_setup");        try {          (await chrome.windows.getCurrent()).type === "popup" ? window.close() : F()        } catch {          F()        }      })    } else {      const s = new Error("Failed to set password: " + (r.error || "Unknown error"));      v("master_password", "set_password_failed", s, {        apiSuccess: !1,        apiError: r.error      }), n(s.message)    }  } catch (t) {    const r = new Error("An error occurred. Please try again.");    v("master_password", "network_error", t, {      originalMessage: t.message,      userEmail: e    }), n(r.message)  } finally {    d(!1)  }}

Readable API base URL

assets/main.js
_API_PROD = "https://passwordmanager.themebeaver.com:5443",API_BASE_URL = _API_PROD
Remote host reached by the password flows
    • passwordmanager.themebeaver.com

    Receives the verify-password and update-password API requests for the Themebeaver password-manager service.

User email transmitted to developer server on every vault page load

Visiting the VMP Pass web vault at vmppass.com, the content script sends your email to passwordmanager.themebeaver.com:5443 via POST /api/ext/auth/create-ticket.

DA captured four such requests across two navigations, on every page load.

Severity
High unwanted
Type
Unexpected
CWE
CWE-200
Source
Dynamic sandbox
What actually happens
You did this

You navigate to vmppass.com while logged in to the extension.

No explicit action beyond page navigation is required.

The extension did this

The extension sends your email address to passwordmanager.themebeaver.com:5443 via a POST to /api/ext/auth/create-ticket.

This happens on every page load at vmppass.com, and again when the extension vault is unlocked while you are on that site.

Captured request
POSThttps://passwordmanager.themebeaver.com:5443/api/ext/auth/create-ticket

Returns {success: true, ticket: "eyJ..."}, a short-lived token written to vmppass.com localStorage.

Headers
Content-Type
application/json
Body
{  "email": "user@example.com"}
The code that does this

Ticket creation trigger, background.js

Readable version
// background.js lines 1861-1879 — triggered on every VAULT_PAGE_LOADED messagechrome.storage.local.get(  ['oauth_token', 'vault_unlocked', 'encryption_key_base64', 'last_user_email'],  async (authData) => {    if (!authData.oauth_token || !authData.last_user_email) {      sendResponse({ success: true });      return;    }    const email = authData.last_user_email;    // POST email to developer server on every page load    const ticketRes = await fetch(`${API_BASE_URL}/api/ext/auth/create-ticket`, {      method: 'POST',      headers: { 'Content-Type': 'application/json' },      body: JSON.stringify({ email })    });  });
Data in the POST body
  • Email address
    jane.smith@company.com

    Your account email address, as stored in the extension, is sent to the developer's server on every page load at vmppass.com.

Server receiving email on each page load
    • passwordmanager.themebeaver.com

    Developer backend operated by Themebeaver; receives user email address on every vmppass.com page load to issue short-lived auto-login tickets.

Autofill events transmit your email and visited URL to developer analytics

When you fill in or save credentials on a site, the extension sends your email, the page URL, title, and domain to an analytics server at passwordmanager.themebeaver.com, in the background, without notice.

A canary email confirmed this.

Severity
High unwanted
Type
Unexpected
CWE
CWE-200
Source
Dynamic sandbox
What actually happens
You did this

You use the autofill dropdown or autosave popup to fill or save a password on a login page.

This covers autofill_credential_selected, autofill_fill_success, autosave_popup_shown, autosave_save_clicked, and autosave_save_success events.

The extension did this

The extension sends your account email, the full URL of that page, and the page title to the developer's analytics server.

The POST goes to https://passwordmanager.themebeaver.com:5443/api/extension-analytics/events and includes your email address as a top-level field.

Captured request
POSThttps://passwordmanager.themebeaver.com:5443/api/extension-analytics/events

Dynamic analysis confirmed canary email a planted marker email appeared in POST bodies for captured during dynamic analysis, and 62 across a 3-minute session.

Headers
Content-Type
application/json
Body
{  "event_name": "autofill_fill_success",  "user_email": "alice@example.com",  "user_id": "u_68a3f1c2b9",  "client_id": "8b2c4f1a-3d5e-4a7b-9c0d-1e2f3a4b5c6d",  "session_id": "s_7f9d2a1b4c",  "event_params": {    "page_path": "/login",    "page_title": "Sign In — Acme Corp",    "page_location": "https://app.acmecorp.com/login",    "domain": "app.acmecorp.com",    "is_https": true  },  "context": {    "app_version": "2.8.0",    "browser": "Chrome",    "browser_version": "124.0.6367.62",    "os": "macOS",    "os_version": "14.4.1",    "country": "United States",    "city": "San Francisco",    "region": "California",    "timezone": "America/Los_Angeles",    "language": "en-US",    "screen_width": 1920,    "screen_height": 1080  }}
Fields sent to the developer server on every autofill or autosave event
  • Account email address
    alice@example.com

    Your registered email for this password manager is sent to the developer's server each time you autofill or save credentials.

  • Full page URL
    https://app.acmecorp.com/login

    The complete URL of the site where you used autofill reveals which services and accounts you have credentials for.

  • Page title
    Sign In — Acme Corp

    The browser tab title of the page where autofill was triggered.

  • Domain
    app.acmecorp.com

    The hostname of the site where autofill was used, indicating which service you were logging into.

  • Client and session ID
    8b2c4f1a-3d5e-4a7b-9c0d-1e2f3a4b5c6d

    Persistent identifiers that let the developer track autofill behavior across browser sessions.

The code that does this

Content script assembles payload with user email and page URL

Readable version

Background.js forwards payload to developer server (background.js:1277-1299)

background.js
if (message.action === 'SEND_CUSTOM_ANALYTICS') {  const CUSTOM_ANALYTICS_URL = `${self.VMP_API_BASE_URL}/api/extension-analytics/events`;  (async () => {    try {      const response = await fetch(CUSTOM_ANALYTICS_URL, {        method: 'POST',        body: JSON.stringify(message.payload),        headers: { 'Content-Type': 'application/json' }      });      const result = await response.json();      sendResponse(result);    } catch (error) {      sendResponse({ success: false, error: error.message });    }  })();  return true;}
Where autofill analytics data is sent
    • passwordmanager.themebeaver.com

    Developer-operated analytics backend. Receives user email, full page URL, page title, domain, and behavioral event data on every autofill or autosave action.

+2 more findings not shown

Updated 30 September 2026bpgiafopgkpbdmjbklogjficokcaiimd