Is Visualping: Website change detection, monitoring and alerts safe?

High risk

Visualping: Website change detection, monitoring and alerts is high risk. Setting up server-side monitoring makes Visualping read the tab's entire localStorage and send it to api.visualping.io as a setItem() replay script.…

visualping.iov4.12.4Chrome Web Store
75Risk

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

Publishers can request a review.

Findings

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-200
SourceAI SANDBOX

Active tab's full localStorage sent to api.visualping.io on Server-tab job setup

Setting up server-side monitoring makes Visualping read the tab's entire localStorage and send it to api.visualping.io as a setItem() replay script.

A test showed all 24 entries sent, including a planted marker confirming exfiltration.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You set up server-side monitoring for a page you're signed into.

In the popup you switch to the Server tab, enter an email, and click Start Monitoring.

The extension did this

The extension reads the tab's entire localStorage and sends it to Visualping's API.

It injects JSON.stringify(localStorage), rebuilds every entry as setItem() calls, and POSTs them inside the new monitoring job.

02EvidenceNETWORK CAPTURE
Captured request
POSThttps://api.visualping.io/v2/jobs/
Observed during dynamic analysis: the POST carried a 'script' preaction (~2,880 chars, 24 localStorage.setItem calls) reproducing the active tab's full localStorage. A planted marker value was present, confirming the storage leaves the device. Real values are redacted here.
Headers
Content-Typeapplication/json
X-Api-Clientvp-chrome-extension-<digest>
Body
{
  "active": true,
  "origin": "chrome",
  "email": "testuser@example.com",
  "url": "https://chatgpt.com/",
  "mode": "VISUAL",
  "target_device": "1",
  "preactions": {
    "active": true,
    "actions": [
      {
        "script": "localStorage.setItem(\"oai/apps/hasSeenOnboarding\", \"<redacted>\"); \nlocalStorage.setItem(\"statsig.stable_id\", \"<redacted>\"); \nlocalStorage.setItem(\"canary_ls_key\", \"PARROT_LS_67890\"); \n"
      },
      {
        "refresh": true
      },
      {
        "wait": "5"
      }
    ]
  }
}
03EvidenceSTORAGE DUMP
What's stored on your device

The page's localStorage is read and rebuilt server-side, often holding login tokens; a planted marker confirmed it leaves the device.

LocationActive tab localStorage (read via injected JSON.stringify(localStorage))
Contents (JSON)
{
  "canary_ls_key": "PARROT_LS_67890 (planted marker, confirmed transmitted)",
  "statsig.stable_id": "<redacted>",
  "oai/apps/hasSeenOnboarding": "<redacted>",
  "<auth/session keys present on the page>": "<redacted>"
}
04EvidenceCODE COMPARE
The code that does this

localStorage capture and script-preaction build

What it actually does
async function dl() {
  // read the active tab's full localStorage
  return new Promise(resolve => {
    chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => {
      chrome.scripting.executeScript({
        target: { tabId: tab.id },
        func: () => JSON.stringify(localStorage)   // every key/value
      }, ([res]) => resolve(JSON.parse(res.result)));
    });
  });
}

function ml(store) {
  let script = '';
  Object.keys(store)
    .filter(k => JSON.stringify(store[k]).length < 2300)  // skip oversize entries
    .forEach(k => {
      script += `localStorage.setItem("${k}", ${JSON.stringify(store[k])}); \n`;
    });
  return script;
}

function fl(store) {
  const script = ml(store);
  return script === '' ? [] : [{ script }, { refresh: true }, { wait: '5' }];
}
// fl(localStorage) is merged into preactions.actions and POSTed to api.visualping.io/v2/jobs/
05EvidenceTHIRD PARTY LIST
Where the localStorage is sent
  • api.visualping.io

    Visualping's backend (Visualping Technologies Inc.). Receives the job containing the tab's localStorage as a setItem() replay script used to recreate your storage state.

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-522
SourceAI SANDBOX

Monitored site cookies sent to api.visualping.io on Server-tab job setup

During server-side monitoring, Visualping reads the page's cookies and sends them to api.visualping.io, which replays them to load the page.

A test showed 24 root-path cookies sent in plaintext, including session and CSRF cookies.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You set up server-side monitoring for a page you're signed into.

In the popup you switch to the Server tab, enter an email, and click Start Monitoring.

The extension did this

The extension reads that page's cookies and sends their values to Visualping's API.

It collects the root-path cookies for the page's domain and POSTs them inside the new monitoring job.

02EvidenceNETWORK CAPTURE
Captured request
POSThttps://api.visualping.io/v2/jobs/
Observed during dynamic analysis: the POST carried 24 root-path cookie objects for the monitored domain. A planted marker cookie was present in the body, confirming the cookies leave the device. Real session cookies were captured in plaintext; their values are redacted here.
Headers
Content-Typeapplication/json
X-Api-Clientvp-chrome-extension-<digest>
Body
{
  "active": true,
  "origin": "chrome",
  "email": "testuser@example.com",
  "url": "https://chatgpt.com/",
  "interval": "60",
  "mode": "VISUAL",
  "target_device": "1",
  "preactions": {
    "active": true,
    "actions": [
      {
        "cookie": {
          "field": "__Host-next-auth.csrf-token",
          "value": "<redacted>",
          "domain": "chatgpt.com"
        }
      },
      {
        "cookie": {
          "field": "oai-did",
          "value": "<redacted>",
          "domain": "chatgpt.com"
        }
      },
      {
        "cookie": {
          "field": "_cfuvid",
          "value": "<redacted>",
          "domain": "chatgpt.com"
        }
      },
      {
        "cookie": {
          "field": "canary_cookie",
          "value": "BIRD_COOKIE_12345",
          "domain": "chatgpt.com"
        }
      }
    ]
  }
}
03EvidenceFIELD TABLE
Cookie fields placed in the job body
FieldValueWhy it matters
Authentication / CSRF cookie
__Host-next-auth.csrf-token = <redacted>Carries your signed-in state for the site. Whoever holds it can act as you on that site without your password.
Device / user identifier cookie
oai-did = <redacted>Ties activity back to your account or browser on that site.
Other root-path cookies
_cfuvid = <redacted>Every cookie set at the domain's root path is included, not just the ones strictly needed to load the page.
04EvidenceCODE COMPARE
The code that does this

Cookie collection and transmission

What it actually does
async function pl(e) {
  const t = cl(e);                       // domain of the monitored URL
  return (await chrome.cookies.getAll({ domain: t }))
    .filter(c => c.name && typeof c.value === 'string' && c.domain)
    .filter(c => c.path === '/')          // keep root-path cookies
    .map(c => ({ cookie: { field: c.name, value: c.value, domain: c.domain } }));
}

// gl(): on Server-tab job creation
Promise.all([pl(e.url), dl()]).then(([cookies, ls]) => {
  let actions = [...cookies, ...fl(ls)];   // cookies + localStorage preactions
  const job = {
    active: true, origin: 'chrome', email: e.email, url: e.url,
    mode: 'VISUAL', target_device: '1',
    preactions: { active: true, actions }  // cookie values travel here
  };
  $.ajax({
    url: 'https://api.visualping.io/v2/jobs/',
    type: 'POST',
    data: JSON.stringify(job),
    headers: { 'Content-Type': 'application/json',
               'X-Api-Client': 'vp-chrome-extension-' + digest }
  });
});
05EvidenceTHIRD PARTY LIST
Where the cookies are sent
  • api.visualping.io

    Visualping's backend (Visualping Technologies Inc.). Receives the monitoring job with the site's cookie values and replays them server-side to load the page in your session.

Updated 17 September 2026fbhjaehnpccniaiedddkbdhgicmcmgng