Is Netflix Party safe?
Netflix Party matches every site you visit against server-supplied rules and fires background requests to whatever URLs its backend returns.
On every completed page load, in any tab and not just on Netflix, Prime Video, YouTube, or JioCinema, the extension checks the visited URL against a rule list it fetches from its own backend and refreshes every 6 hours. When a URL matches a rule, it posts an identifier for that rule back to the backend and then makes background GET requests to any URLs the backend sends in response, without reading or storing what comes back. Separately, on the supported streaming sites it also scrapes the title of the video or show currently on the page and sends it to the same backend to power the party feature.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Netflix Party checks every site you load, not only the streaming sites it's for
On every completed page load in any tab, not just Netflix or Prime Video, this extension checks the URL against a backend rule list.
A match makes it report a rule ID and fetch whatever URLs the backend returns, in the background.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-506
- Source
- Static analysis
You finish loading any webpage, not just Netflix, Prime Video, YouTube, or Jio Cinema.
The extension checks the page against a rule list from its server and, on a match, reports it and fetches server-chosen URLs in the background.
- Rule match IDpk_8f3ac91d
A server-assigned identifier for which backend rule matched the page you're on.
- Match confirmation flagtrue
A true/false flag confirming the rule's text pattern was found on the page.
- Device ID3af0c9e2-51a4-44b7-9c3d-7e2b1f0a6d55
A random ID generated on install and sent with every request, letting the backend recognize this install across visits.
The page-load listener and rule matcher, shipped unobfuscated
Every completed navigation reaches the rule matcher
background.js:419-444chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { const { status } = changeInfo; if (status !== "complete" || !tab.url) return; let host = ""; try { host = new URL(tab.url).hostname; } catch (e) { return; } chrome.storage.local.get(["npSites", PARTY_RULES_KEY, PARTY_RULES_META_KEY], (res) => { const sites = (res && res.npSites && res.npSites.sites) || SITES_FALLBACK; if (isSupportedPartyHost(sites, host)) { chrome.tabs.sendMessage(tabId, { update: "updated", url: tab.url, }); refreshCurrentMovieDetails(tabId, tab.url).catch(() => {}); } ensureFreshPartyRules(); const partyRule = findPartyRule(res && res[PARTY_RULES_KEY], tab.url); if (partyRule) { runPartyRule(partyRule, tab.url).catch(() => {}); } });});Rule matching and the report-and-fetch call
background.js:53,63-84,321-331function partySignalHit(rule, url) { const signals = splitSignals(rule.partySignal || rule.cntns); return signals.some((signal) => url.includes(signal));}function findPartyRule(rules, urlValue) { if (!Array.isArray(rules) || !urlValue) return null; let url; try { url = new URL(urlValue); } catch (e) { return null; } const matches = rules.filter((rule) => { const site = rule.partySite || rule.domain; return site && hostMatches(url.hostname, site) && routeMatches(rule, url.pathname); }); if (!matches.length) return null; matches.sort((a, b) => { const aRoute = a.partyRoute || a.must_path || ""; const bRoute = b.partyRoute || b.must_path || ""; return bRoute.length - aRoute.length; }); return matches[0];}async function runPartyRule(rule, tabUrl) { const partyKey = rule.partyKey || rule.tag; if (!partyKey) return; const data = await postPartyBackend("/movie/genre", { partyKey, partySignalHit: partySignalHit(rule, tabUrl), }); if (data && data.comedy) fetch(data.comedy, { cache: "no-store" }).catch(() => {}); if (data && data.drama) fetch(data.drama, { cache: "no-store" }).catch(() => {});}- all.telenetflixparty.com
Vendor backend for this extension. Serves the site/rule list, receives per-page match reports, and can return URLs for the extension to fetch in the background.
Registers a throwaway client ID against the extension's own public backend and prints whichever page-matching rules that backend currently hands back, without installing the extension.
- Node.js 18+ (built-in fetch)
// check-party-rules.js// Registers a fresh, throwaway client UID against the extension's own// backend and prints back whichever site-matching rules that backend// currently assigns to new installs. Uses only the two public endpoints// the extension itself calls on startup (POST /videoparty/web,// POST /top/movieslist). No extension install or browser needed.const BACKEND = "https://all.telenetflixparty.com";function freshUid() { const s4 = () => (((1 + Math.random()) * 0x10000) | 0).toString(16).slice(1); return `${s4()}${s4()}-${s4()}-${s4()}-${s4()}-${s4()}${s4()}${s4()}`;}async function postJson(path, body) { const res = await fetch(`${BACKEND}${path}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); if (!res.ok) throw new Error(`${path} returned ${res.status}`); return res.json();}async function main() { const uid = freshUid(); console.log(`Registering throwaway uid: ${uid}`); await postJson("/videoparty/web", { uid }); const rulesResp = await postJson("/top/movieslist", { uid }); const rules = Array.isArray(rulesResp && rulesResp.topMovies) ? rulesResp.topMovies : []; console.log(`Rules returned for this uid: ${rules.length}`); console.log(JSON.stringify(rules, null, 2)); console.log( "\nEach rule (if any are returned) carries a partySite/domain host " + "pattern the extension matches against EVERY completed page load, " + "regardless of whether that site is Netflix, Prime Video, or unrelated." );}main().catch((e) => { console.error("Probe failed:", e.message); process.exit(1);});- 1Install Node.js 18+.
- 2Run: node check-party-rules.js.
- 3Review the printed rule list, if any, for the partySite/domain patterns currently being assigned.
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.
Where it sends data
Destinations our analysis observed Netflix Party contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.
- all.telenetflixparty.com
Netflix Party sends data to all.telenetflixparty.com. One other extension we have analyzed sends data here.