Is ЮБуст - VPN для YouTube. Обход блокировки Ютуб без ВПН. VPN для браузера safe?

Medium risk

ЮБуст 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.…

Uboostv8.11.16Chrome Web Store
49Risk
Who publishes it

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.

Publisher
Uboost
Declared legal entity
IP Zamolotskikh
Registered address
Bogenbai Batyr Street 86, Almaty, Алматы 050000, KZ
Registered contact
Uboost

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.

uboost.space
Also called by 3 other listings: Врубель, Открывашка, перемен-vpn-с-российским
ubst.space
Also called by 3 other listings: Врубель, Открывашка, перемен-vpn-с-российским
naruzhu.click
Also called by 4 other listings
staticfiles.cukubst.top
Also called by 4 other listings

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
What actually happens
You did this

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.

The extension did this

ЮБуст 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.

Captured request
POSThttps://www.google-analytics.com/mp/collect?measurement_id=G-XCPV2XK66M&api_secret=<redacted>

204 No Content, Google Analytics confirms event accepted. Four such POSTs were observed during dynamic analysis for events 'install' and 'user_created'.

Headers
Origin
chrome-extension://jddgbeighonaipjikdnfdpiefhoomlae
Content-Type
text/plain;charset=UTF-8
Body
{  "client_id": "c4aacd99-66ff-46ba-8dba-72e5c45176e7",  "events": [    {      "name": "user_action",      "params": {        "action": "install",        "category": "extension",        "session_id": "1776464941481",        "engagement_time_msec": 100      }    }  ]}
What ends up in the developer's Google Analytics dashboard for your install
  • Your permanent client ID
    c4aacd99-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 ID
    304bd233-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 ID
    1776464941481

    Groups the events from one browsing session together. Resets after 30 minutes of inactivity.

  • Event name
    user_action / install

    Reported action: install, user_created, page_view, manual_start, video_redirect, extension-conflict types, extension_error.

  • Conflicting extension ID + name
    cjpalhdlnbpafiamejdnhcphjbkeiagm / 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 version
    8.10.3

    Which build of ЮБуст is installed.

  • Error message + type
    Failed 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 code that does this

The shipped tracker class, with credentials baked in

Readable version

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);
What's stored on your device

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)
Contents
{  "clientId": "e316df7b-1d92-4aa0-b66d-eed03fe588c7",  "deviceId": "304bd233-9b22-4f7c-bebc-e9fb1173a3cf",  "sessionData": {    "timestamp": 1776464941481,    "session_id": "1776464941481"  }}
Where each piece of telemetry ends up
    • 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.

Reproduce it yourself

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.

Requires
  • Chrome with Developer mode enabled
  • ЮБуст installed and onboarded (so chrome.storage.local has clientId/deviceId)
uboost-ga-decoder.js · js
// 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"');})();
How to run it
  1. 1Open chrome://extensions, enable Developer mode.
  2. 2Click 'service worker' under ЮБуст.
  3. 3Paste the script in Console, Enter; it prints stored IDs.
  4. 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
What actually happens
You did this

You are watching a video on YouTube.

The extension did this

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 code that does this

The background scheduler and the content-script overlay injector, from the shipping source.

Readable version

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 code that does this

The page-injected bridge letting the content script drive YouTube's player, in the MAIN world.

Readable version

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 }, '*');});
Page DOM modified

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
Before
<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>
After the extension changed it
<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://&lt;midpointMediaUrls from remote config&gt;" style="width:100%;height:100%;object-fit:contain;"></iframe>  </div></div>
When this fires

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.

Observation

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.

Updated 30 September 2026jddgbeighonaipjikdnfdpiefhoomlae