Is ЮБуст - VPN для YouTube. Обход блокировки Ютуб без ВПН. VPN для браузера safe?
ЮБуст is medium risk. ЮБуст ships a hardcoded GA ID (G-XCPV2XK66M) and API secret, logging installs, signups, rival extensions found, and other events. Two permanent UUIDs, made on first run, tag every event, tracking one install across restarts.…
Who publishes itIP Zamolotskikh - no other listings under this identity, 4 shared hostnames
IP Zamolotskikh - no other listings under this identity, 4 shared hostnames
What this publisher told the store about itself, and the other listings that told it the same thing.
Shared hosts - 4 hostnames
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.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Telemetry to Google Analytics with hardcoded credentials and persistent IDs
ЮБуст ships a hardcoded GA ID (G-XCPV2XK66M) and API secret, logging installs, signups, rival extensions found, and other events.
Two permanent UUIDs, made on first run, tag every event, tracking one install across restarts.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Dynamic sandbox
You install ЮБуст or finish onboarding to create your free-trial account.
Same path fires on every browser restart for session events, on every detected conflict with another VPN/ad-blocker extension, and on every uncaught error in the service worker.
ЮБуст posts a JSON event to GA tagged with two permanent per-install IDs, using an API secret hardcoded in the extension.
The same event pipeline carries 'install', 'user_created', 'manual_start', 'video_redirect', 'proxy_controlled_by_other_extension', 'vpn_extension_conflict', 'ad_blocker_conflict', and other lifecycle/observability events, each one stitched to the same persistent client_id.
204 No Content, Google Analytics confirms event accepted. Four such POSTs were observed during dynamic analysis for events 'install' and 'user_created'.
- Origin
- chrome-extension://jddgbeighonaipjikdnfdpiefhoomlae
- Content-Type
- text/plain;charset=UTF-8
{ "client_id": "c4aacd99-66ff-46ba-8dba-72e5c45176e7", "events": [ { "name": "user_action", "params": { "action": "install", "category": "extension", "session_id": "1776464941481", "engagement_time_msec": 100 } } ]}- Your permanent client IDc4aacd99-66ff-46ba-8dba-72e5c45176e7
A random UUID made on first run, stored forever. Every event carries it, letting the developer stitch your history across sessions.
- Your permanent device ID304bd233-9b22-4f7c-bebc-e9fb1173a3cf
A second UUID kept in storage and a first-party cookie. Clearing storage doesn't remove it; the cookie repopulates it.
- Session ID1776464941481
Groups the events from one browsing session together. Resets after 30 minutes of inactivity.
- Event nameuser_action / install
Reported action: install, user_created, page_view, manual_start, video_redirect, extension-conflict types, extension_error.
- Conflicting extension ID + namecjpalhdlnbpafiamejdnhcphjbkeiagm / uBlock Origin
If another VPN, proxy, or ad blocker is installed, ЮБуст names it and its store ID, so the developer learns which privacy tools you run.
- YouTube tab URL (on video_redirect)https://www.youtube.com/watch?v=dQw4w9WgXcQ
When the extension intercepts a video to redirect it through its proxy, the YouTube URL of that tab is sent as the event label.
- Extension version8.10.3
Which build of ЮБуст is installed.
- Error message + typeFailed to fetch / user_creation_failed
Any internal error is sent as an 'extension_error' GA event, and also to the developer's own Sentry server.
The shipped tracker class, with credentials baked in
GoogleAnalyticsTracker — annotated
const Tracker = new class GoogleAnalyticsTracker { // Reads the persistent UUID from chrome.storage.local under StorageKeys.ClientId. // If missing, mints a new UUID and saves it. Result: a per-install ID that // survives forever (until the user explicitly clears the extension's storage). async getOrCreateClientId() { const { clientId } = await Storage.get(StorageKeys.ClientId); if (typeof clientId === 'string') return clientId; const fresh = self.crypto.randomUUID(); await Storage.set({ [StorageKeys.ClientId]: fresh }); return fresh; } // Standard GA4 30-minute rolling session window. async getOrCreateSessionId() { const { sessionData } = await Storage.get(StorageKeys.SessionData); let session = sessionData ? { ...sessionData } : null; const now = Date.now(); if (session) { if ((now - session.timestamp) / 60000 > 30) session = null; else { session.timestamp = now; await Storage.set({ sessionData: session }); } } if (!session) { session = { session_id: now.toString(), timestamp: now }; await Storage.set({ sessionData: session }); } return session.session_id; } // Builds a GA4 Measurement Protocol payload and POSTs it to Google. // The measurement_id and api_secret are HARDCODED in the URL — anyone // who unzips the extension can read them; conversely, every install of // ЮБуст is reporting against the same GA property keyed on client_id. async sendEvent({ name, params }) { try { const [client_id, session_id] = await Promise.all([ this.getOrCreateClientId(), this.getOrCreateSessionId(), ]); const body = { client_id, events: [{ name, params: { ...params, session_id, engagement_time_msec: 100 }, }], }; const url = 'https://www.google-analytics.com/mp/collect' + '?measurement_id=G-XCPV2XK66M' + '&api_secret=<redacted>'; const resp = await fetch(url, { method: 'POST', body: JSON.stringify(body) }); if (!resp.ok) console.error('Failed to send GA event:', await resp.text()); } catch (e) { console.error('Error sending GA event:', e); } } trackPageView(page) { return this.sendEvent({ name: 'page_view', params: { page_title: page, page_location: chrome.runtime.getURL(page) }, }); } trackUserAction(action, category, label) { return this.sendEvent({ name: 'user_action', params: { action, category, label }, }); } trackError(error_message, error_type) { return this.sendEvent({ name: 'extension_error', params: { error_message, error_type }, }); }};Conflict-extension reporters — annotated
// Whenever ЮБуст walks chrome.management to look for other VPN / proxy /// ad-blocker / 'internal' extensions, it reports each conflict to GA along// with the OTHER extension's Chrome Web Store ID and human-readable name.// Result: the developer's GA dashboard tells them which competing privacy// tools each one of their users has installed.if (proxyConflict.hasConflictingExtension) { Tracker.trackUserAction( 'proxy_controlled_by_other_extension', proxyConflict.conflictingExtensionName ?? 'unknown', // e.g. 'AdBlock Plus' proxyConflict.conflictingExtensionId, // e.g. 'cfhdojbkjhnklbpkdaibdccddilifddb' );}// Same shape for internal_extension_conflict, vpn_extension_conflict,// ad_blocker_conflict.// Onboarding / lifecycle:await Tracker.trackUserAction('install', 'extension'); // first installawait Tracker.trackUserAction('update', 'extension', previousVersion); // version bumpawait Tracker.trackUserAction('user_created', 'premium'); // premium signupawait Tracker.trackUserAction('manual_start', 'proxy'); // proxy started// YouTube video routing — the YouTube URL is forwarded as the GA event label.await Tracker.trackUserAction('video_redirect', 'youtube', youtubeUrl);clientId feeds GA; deviceId feeds the dev's backend. Both mint once, never cleared; deviceId is also a cookie, surviving storage clears.
- Location
- chrome.storage.local, keys 'clientId', 'deviceId', 'sessionData' (and a sibling first-party cookie 'deviceId' on the developer's cookieDomain)
{ "clientId": "e316df7b-1d92-4aa0-b66d-eed03fe588c7", "deviceId": "304bd233-9b22-4f7c-bebc-e9fb1173a3cf", "sessionData": { "timestamp": 1776464941481, "session_id": "1776464941481" }}- www.google-analytics.com
Receives every Measurement Protocol POST: installs, signups, conflict reports, video redirects, errors. Under GA4 property G-XCPV2XK66M.
- sentry-ws-1.vpnn.space
Self-hosted Sentry owned by the same developer. Receives exceptions, rejections, and arbitrary extras. Tagged extension_code='youboost' (service_worker.js line 1947).
- uboost.space / ubst.space
The developer's backend. Receives the deviceId UUID on trial, signup, and update checks, plus the same UUID as a cookie, re-identifying your install if storage is cleared.
Run this in the ЮБуст service worker's DevTools console to intercept every Google Analytics POST the extension makes and print the full URL (with hardcoded creds), the JSON body, and the resolved client_id/session_id/event params. Confirms the hardcoded credentials and persistent IDs without needing a network proxy.
- Chrome with Developer mode enabled
- ЮБуст installed and onboarded (so chrome.storage.local has clientId/deviceId)
// uboost-ga-decoder.js// Drop into the ЮБуст service worker DevTools console:// chrome://extensions → enable Developer mode → click the// 'service worker' link under ЮБуст → paste below.//// Wraps fetch() so every google-analytics.com/mp/collect call is// dumped in full BEFORE it hits the wire. Also dumps the persistent// IDs from chrome.storage.local on load.(async () => { // 1. Show the persistent IDs the extension is using to tag your install. const keys = await chrome.storage.local.get(['clientId', 'deviceId', 'sessionData']); console.log('[YOUBOOST_IDS] persistent identifiers in chrome.storage.local:'); console.table(keys); // 2. Hook fetch to capture every GA Measurement Protocol POST. const origFetch = self.fetch.bind(self); self.fetch = async function (input, init) { const url = typeof input === 'string' ? input : input.url; if (url && url.includes('google-analytics.com/mp/collect')) { const u = new URL(url); const measurement_id = u.searchParams.get('measurement_id'); const api_secret = <redacted>('api_secret'); let body = init && init.body; try { body = JSON.parse(body); } catch {} console.log('[YOUBOOST_GA] outbound event captured:'); console.log(' hardcoded measurement_id:', measurement_id); console.log(' hardcoded api_secret :', api_secret); console.log(' body :', body); } return origFetch(input, init); }; console.log('[YOUBOOST_GA_DECODER] installed. Trigger an event:'); console.log(' - reload the extension to fire "install"/"update"'); console.log(' - install another VPN/ad-blocker to fire "*_conflict"'); console.log(' - open a YouTube video routed through the proxy to fire "video_redirect"');})();- 1Open chrome://extensions, enable Developer mode.
- 2Click 'service worker' under ЮБуст.
- 3Paste the script in Console, Enter; it prints stored IDs.
- 4Trigger an event (add a blocker, reload). Each GA POST is dumped with its secret.
Injects its own ad overlays and upgrade banners into the YouTube player
Watching YouTube, this extension can pause your video and cover it with a full-screen overlay loading a remote ad page in an iframe, plus periodic upgrade banners, blocking keyboard shortcuts while up.
Whether it runs is set remotely.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-200
- Source
- Dynamic sandbox
You are watching a video on YouTube.
On a schedule the extension pauses your video and covers the player with its own full-screen overlay that loads a remote ad/upsell page, or shows a premium-upgrade banner.
A background alarm (ShowMidRoll / ShowAdPremiumBanner) messages the active YouTube tab; the content script injects the overlay and blocks keyboard shortcuts until it closes.
The background scheduler and the content-script overlay injector, from the shipping source.
Background: midroll alarm queries the active YouTube tab and tells it to show a midpoint
// Background alarm handler for the scheduled mid-roll.if (alarm.name === Alarms.ShowMidpointMedia) { const { hasPremium } = await getLocal(Keys.HasPremium); const { featuresList } = await featureStore.getSnapshotAsync(); const midpointEnabled = Boolean(featuresList?.[Features.MidpointMedia]); if (hasPremium || !midpointEnabled) return; // skip paying users / disabled flag const tabs = await chrome.tabs.query({ active: true, currentWindow: true, url: ['*://*.youtube.com/*'], }); await Promise.all(tabs.map(t => t.id ? chrome.tabs.sendMessage(t.id, { action: ContentAction.ShowMidpoint }) : null));}Content script: builds a black full-size overlay with an iframe whose src comes from remote config (midpointMediaUrls)
// Content script: inject the full-screen ad overlay over the player.const overlay = document.createElement('div');overlay.id = OVERLAY_ID;overlay.style.cssText = 'position:absolute;top:0;left:0;width:100%;height:100%;' + 'background:black;z-index:9999;display:flex;justify-content:center;align-items:center;';const frame = document.createElement('iframe');frame.id = IFRAME_ID;frame.src = midpointMediaUrls[regionKey]; // URL comes from downloaded remote configframe.style.cssText = 'width:100%;height:100%;object-fit:contain;';window.addEventListener('message', onFrameMessage);overlay.appendChild(frame);moviePlayer.appendChild(overlay); // moviePlayer = document.getElementById('movie_player')Content script: pauses the player and installs capture-phase keydown/keyup handlers that swallow YouTube shortcut keys
// Content script: pause playback and swallow YouTube keyboard shortcuts.const blockKey = (e) => { if (['', 'ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'k','K','j','J','l','L','m','M','f','F','i','I'].includes(e.key)) { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); }};const pauseForOverlay = () => { postToPlayerBridge('pauseVideo'); // YT_METHOD_CALL -> injected wrapper document.querySelector('video')?.pause(); document.getElementById('movie_player')?.pauseVideo?.(); document.addEventListener('keydown', blockKey, true); // capture phase document.addEventListener('keyup', blockKey, true);};The page-injected bridge letting the content script drive YouTube's player, in the MAIN world.
watchCoordinator.js: listens for YT_METHOD_CALL window messages and calls pauseVideo / playVideo / getPlayerState on the real player
// Runs in the page MAIN world (web-accessible resource).window.addEventListener('message', (event) => { const data = event.data; // Only accept the extension's own tagged messages. if (!(data && data.source === 'YT_API_WRAPPER' && data.type === 'YT_METHOD_CALL' && ['pauseVideo','playVideo','getPlayerState'].includes(data.method))) return; const player = document.getElementById('movie_player'); if (!isYoutubePlayer(player)) return; const result = data.method === 'getPlayerState' ? player.getPlayerState() // -1..5 player state : (player[data.method](), true); window.postMessage({ source: 'YT_API_WRAPPER', type: 'YT_METHOD_RESULT', method: data.method, result }, '*');});A full-size black overlay div (z-index 9999) holding an ad/upsell iframe is appended over the paused player; the iframe URL comes from downloaded remote config.
- Target
- the YouTube player container (#movie_player) on youtube.com/watch
<div id="movie_player" class="html5-video-player playing-mode"> <div class="html5-video-container"> <video src="blob:https://www.youtube.com/..."></video> </div> <!-- YouTube's own controls --></div><div id="movie_player" class="html5-video-player paused-mode"> <div class="html5-video-container"> <video src="blob:https://www.youtube.com/..."></video> <!-- paused by extension --> </div> <!-- injected by the extension: --> <div id="midpoint_overlay" style="position:absolute;top:0;left:0;width:100%;height:100%;background:black;z-index:9999;display:flex;align-items:center;justify-content:center;"> <iframe id="YT_API_WRAPPER_FRAME" src="https://<midpointMediaUrls from remote config>" style="width:100%;height:100%;object-fit:contain;"></iframe> </div></div>On an interval
Mid-roll overlays and premium-upgrade banners are driven by chrome.alarms, not by anything you do. ShowMidRoll injects the full-screen ad overlay; ShowAdPremiumBanner toggles the banner. Both are skipped for users marked as having premium and are gated by feature flags pulled from remote config, so the cadence and whether they run at all are set by the extension's servers.
What was observed: the YouTube content scripts (including the mid-roll / premium-banner code) were confirmed loaded on a YouTube watch page during dynamic analysis, and the remote feature flags that enable this behavior (video-pre-roll, sidebar-ads) were active in the extension's feature store. The exact ad/upsell pages served are not fixed in the extension — they are URLs the extension downloads from its servers (midpointMediaUrls) and can be changed remotely without an update, so the specific creative shown to any given user is not determined by the shipped code alone.