Is VCU - The Co-Browsing Network safe?
VCU records the URL, title, and search terms of every page you visit and writes them to a database other logged-in users can read.
On every completed page load, the extension captures the current tab's URL, title, and — for about 90 major sites (Google, WhatsApp, Amazon, Realtor.com, healthgrades.com, and similar) — the contents of specific search or message fields. Once you're signed into a VCU account, this information is written to VCU's Firebase database, keyed by a hash of the URL. Any other logged-in VCU user who visits (or later visits) the same page can read that entry and see your exact URL, page title, and the captured search or message text.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
VCU writes visited URLs and search text to a shared Firebase database
Code analysis shows the extension logs completed page loads on about 90 sites, keeps the matched search or message text, and, once you sign into a VCU account, writes the URL, that text and the page title to Firebase, keyed by a URL hash.
You sign into a VCU account, then finish loading a page on one of about 90 tracked sites, such as a Healthgrades or Google search.
The same happens on retailers, real-estate sites, legal-directory sites, and chat apps like WhatsApp and Slack.
The extension records the page's URL, the matched search or message text, and its title, then writes them to a shared Firebase database keyed by a hash of the URL.
Any other signed-in VCU user who reaches the same URL can read that entry.
Domain allowlist and query filter deciding what's retained (background.js)
"abc.com/": ["show"],
"abcnews.go.com/": ["search"],
"alibaba.com/products": ["SearchText"],
"aliexpress.com/wholesale": ["SearchText"],
"amazon.com/": ["field-keywords", "show"],
"apnews.com/": ["search"],
"autotrader.com/": ["search"],
"avvo.com/": ["search"],
"bandcamp.com/": ["track"],
"banggood.com/search": ["q"],
"bbc.co.uk/": ["programme"],
"bbc.com/": ["search"],
"bestbuy.com/site/searchpage": ["query"],
"bing.com/search": ["q"],
"bostonglobe.com/": ["search"],
"bradsdeals.com/search": ["q"],
"cargurus.com/": ["search"],
"cars.com/": ["search"],
"cbs.com/": ["show"],
"cbsnews.com/": ["search"],
"chicagotribune.com/": ["search"],
"cnn.com/": ["search"],
"costco.com/CatalogSearch": ["keyword"],
"coupons.com/": ["q"],
"craigslist.org/search": ["query"],
"cwtv.com/": ["show"],
"dailymotion.com/": ["video"],
"dealcatcher.com/search": ["search", "q"],
"dealhack.com/search": ["q"],
"dealigg.com/search": ["q"],
"dealighted.com/search": ["q"],
"dealmac.com/search": ["q"],
"dealmoon.com/search": ["search", "q"],
"dealnews.com/search": ["search", "q"],
"dealoftheday.com/search": ["q"],
"deals2buy.com/search": ["q"],
"dealsea.com/search": ["q"],
"dealsplus.com/search": ["q"],
"dhgate.com/wholesale": ["search"],
"dhl.com/en/express/tracking.html": ["AWB"],
"discord.com/": ["message"],
"duckduckgo.com/": ["q"],
"ebates.com/search": ["query"],
"ebay.com/": ["_nkw"],
"edmunds.com/": ["search"],
"etsy.com/": ["q"],
"facebook.com/": ["q", "id"],
"fedex.com/bpost": ["q"],
"findlaw.com/": ["search"],
"flickr.com/": ["photo"],
"fox.com/": ["show"],
"foxnews.com/": ["search"],
"gearbest.com/": ["q"],
"google.com/search": ["q", "oq"],
"groupon.com/browse": ["query"],
"hbo.com/": ["show"],
"healthgrades.com/": ["search"],
"homedepot.com/s": ["search"],
"huffpost.com/": ["search"],
"hulu.com/": ["show"],
"iheart.com/": ["station"],
"imdb.com/": ["title"],
"instagram.com/": ["q", "p"],
"kbb.com/": ["search"],
"kik.com/": ["chat"],
"kmart.com/search": ["q"],
"last.fm/": ["track"],
"latimes.com/": ["search"],
"lawyers.com/": ["search"],
"lightinthebox.com/index.php": ["main_page", "q"],
"line.me/": ["chat"],
"linkedin.com/": ["keywords", "article"],
"livingSocial.com/search": ["query"],
"lowes.com/search": ["q"],
"macys.com/shop/featured": ["q"],
"mixcloud.com/": ["track"],
"myspace.com/": ["song"],
"nbc.com/": ["show"],
"nbcnews.com/": ["search"],
"netflix.com/": ["show"],
"newegg.com/Product/ProductList.aspx": ["Submit", "DEPA"],
"nolo.com/": ["search"],
"npr.org/": ["program", "search"],
"nydailynews.com/": ["search"],
"nypost.com/": ["search"],
"nytimes.com/": ["search"],
"officedepot.com/a/browse": ["Ntt"],
"overstock.com/search": ["keywords"],
"pandora.com/": ["station"],
"pinterest.com/": ["q", "pin"],
"radio.com/": ["station"],
"ratemds.com/": ["search"],
"realtor.com/": ["search"],
"reddit.com/": ["q", "comments"],
"redfin.com/": ["search"],
"retailmenot.com/coupons": ["query"],
"reuters.com/": ["search"],
"reverbnation.com/": ["track"],
"samsclub.com/sams/search/searchResults.jsp": ["searchTerm"],
"savings.com/search": ["q"],
"sears.com/search": ["keyword"],
"sfgate.com/": ["search"],
"shopathome.com/search": ["q"],
"shopular.com/search": ["q"],
"showtime.com/": ["show"],
"skype.com/": ["chat"],
"slack.com/": ["message"],
"slickdeals.net/": ["query"],
"snapchat.com/": ["story"],
"soundcloud.com/": ["track"],
"spotify.com/": ["track"],
"staples.com/office/supplies": ["q"],
"target.com/s": ["searchTerm"],
"telegram.com/": ["msg"],
"thekrazycouponlady.com/": ["search"],
"tiktok.com/": ["video"],
"tripadvisor.com/": ["search"],
"truecar.com/": ["search"],
"trulia.com/": ["search"],
"tumblr.com/": ["q", "post"],
"tunein.com/": ["station"],
"twitch.tv/": ["clip"],
"twitter.com/": ["q", "status"],
"ups.com/ups.app": ["q"],
"usatoday.com/": ["search"],
"usps.com/search": ["text"],
"viber.com/": ["chat"],
"vimeo.com/": ["video"],
"vistaprint.com/search": ["q"],
"vitals.com/": ["search"],
"walmart.com/search": ["query"],
"washingtonpost.com/": ["search"],
"wayfair.com/keyword.php": ["keyword"],
"whatsapp.com/": ["message"],
"wikipedia.org/": ["search"],
"wish.com/search": ["q"],
"wsj.com/": ["search"],
"yahoo.com/": ["p"],
"yelp.com/": ["search"],
"youtube.com/watch": ["v", "list", "index"],
"zillow.com/": ["search"],
"zocdoc.com/": ["search"]
}function i(t) {
const n = new URL(t),
r = n.pathname,
i = new URLSearchParams(n.search),
o = new URLSearchParams,
u = e[n.hostname.split(".").slice(-2).join(".") + n.pathname] || [];
return i.forEach(((t, n) => {
u.includes(n) && o.append(n, t)
})), o.size ? r + "?" + o.toString() : r
}Tab-update listener and forwarder to the chat iframe (background.js)
chrome.tabs.onUpdated.addListener(((t, n, r) => {
n.status === chrome.tabs.TabStatus.COMPLETE && a(t).then((n => {
n && s(t, r.url, r.title)
}))
}))function s(t, n, r) {
const e = new URL(n);
chrome.tabs.sendMessage(t, {
m: "showIframe"
}, {
frameId: 0
}, (() => {
chrome.runtime.lastError
})), chrome.tabs.sendMessage(t, {
m: "initNewUrl",
urlInfo: {
url: e.hostname + i(n),
urlShort: i(n),
domain: e.hostname,
title: o(r),
tabId: t
}
}, void 0, (() => {
chrome.runtime.lastError
}))
}The chat iframe writing the URL and title to Firebase once you're signed in (chats.js)
setRoomStats({
state: t,
commit: e
}, n) {
if ((0, Wg.debugConsoleLog)("🏷️ ~ setRoomStats ~ payload:", n), !t.user) return;
const r = "/" === n.urlShort,
i = {
url: n.url,
title: n.title || (0, Wg.domainToTitle)(n.domain),
time: Date.now()
},
o = {
url: n.domain,
title: r ? n.title : (0, Wg.domainToTitle)(n.domain),
isHomePageUrl: r,
isRootUrl: !0,
time: Date.now() - 1
};
pF.ref(`roomStats/${n.urlHash}/info`).set(i).then((() => {
e("setWebsiteStatsCache", {
roomId: n.urlHash,
value: {
info: i
}
})
})).catch((() => {})), pF.ref(`roomStats/${n.domainHash}/info`).set(o).then((() => {
e("setWebsiteStatsCache", {
roomId: n.domainHash,
value: {
info: o
}
})
})).catch((() => {}))
},
registerOnlineAtLocation({
state: t,
dispatch: e,
commit: n
}, r) {
(0, Wg.debugConsoleLog)("🏷️ ~ registerOnlineAtLocation ~ payload:", r), n("setTabOnlinePayload", r);
let i = !!t.user;
const o = vF.onAuthStateChanged((t => {
t && !i ? (chrome.runtime.sendMessage({
m: "logged-in"
}), o && o()) : t || (i = !1)
}));
if (!t.user) return;
const a = pF.ref(".info/connected"),
s = function(e, n, r = !1, i = !1) {
(0, Wg.debugConsoleLog)("🏷️ ~ subscribeToOnline ~ ref, url:", e.path, n);
const o = uF(),
s = e.child(o);
a.on("value", (async t => {
if (!0 === t.val()) {
i || await (0, Wg.delay)(100);
const t = Date.now();
await s.onDisconnect().remove(), await s.set(Date.now()), (0, Wg.debugConsoleLog)(`🏷️ Got online for ${n} at ${t}`)
} else await s.remove()
})), chrome.runtime.onMessage.addListener((e => {
("logging-out" === e.m || ("disconnect" === e.m || "hideTabs" === e.m && !r) && e.instanceId === t.instanceId) && (a.off("value"), s.remove())
}))
},
c = t.user.uid,
l = r.urlHash,
u = r.domainHash,
d = pF.ref(`online/${l}/${c}`),
h = pF.ref(`online/${u}/${c}`),
f = pF.ref(`publicOnline/${c}/${u}`),
p = pF.ref(`publicOnline/${c}/${l}`),
v = pF.ref(`publicOnline/${c}/${zg.on}`);
return chrome.runtime.sendMessage({
m: "foward-runtime-message",
message: {
m: "disconnect",
instanceId: t.instanceId
}
}).then((() => {
t.tabsHidden || (s(d, r.url), s(h, r.domain, !1, !0), "/" !== r.urlShort && s(p, r.url), s(f, r.domain, !1, !0)), s(v, "/", !0, !0), a.on("value", (async t => {
!0 === t.val() && e("setRoomStats", r)
}))
})), !0
}| Field | Value | Why it matters | |
|---|---|---|---|
Page URL + matched search text | https://www.healthgrades.com/search?search=knee+replacement+surgeon | The exact URL you're on, plus whichever search or message field the allowlist kept for that site. | |
Page title | knee replacement surgeon - Healthgrades | The browser tab's title at the time of the visit, stored alongside the URL. | |
URL hash (database key) | roomStats/-N3f7QaZ1kP9xQzR2b8H/info | A hash of the URL used as the record's key. Anyone who visits the same URL, or is given the hash, lands on the same record. | |
Your VCU account ID | uid: 7f3a9c21-88de-4b6a-9c11-2ee0a9f74210 | Your VCU user ID is attached to the presence write, tying the page visit to your account. |
- vcu-extension.firebaseio.com
Firebase Realtime Database project operated by VCU for presence/page-visit records; its security rules, not the extension, govern read access beyond VCU's own client.
Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.