Is Visualping: Website change detection, monitoring and alerts safe?
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.…
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
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.
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 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.
| Content-Type | application/json |
| X-Api-Client | vp-chrome-extension-<digest> |
{
"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"
}
]
}
}The page's localStorage is read and rebuilt server-side, often holding login tokens; a planted marker confirmed it leaves the device.
Active tab localStorage (read via injected JSON.stringify(localStorage)){
"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>"
}localStorage capture and script-preaction build
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/- 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.
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.
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 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.
| Content-Type | application/json |
| X-Api-Client | vp-chrome-extension-<digest> |
{
"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"
}
}
]
}
}| Field | Value | Why 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. |
Cookie collection and transmission
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 }
});
});- 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.