Is VPN Наружу для YouTube. Обход блокировки YouTube бесплатно safe?

Medium risk

The extension fetches its proxy configuration and PAC script from remote servers with no integrity verification.

On every connection, the extension retrieves a configuration JSON from storage.googleapis.com (with a Yandex Cloud fallback) to obtain its proxy server address and the URL of a PAC script. The PAC script itself is downloaded, decompressed client-side, and applied directly to browser proxy settings without any signature or integrity check, meaning a compromised or substituted config file could redirect all browser traffic. The extension also enumerates all installed browser extensions every 30 minutes and writes a user ID cookie to a domain specified by the same remote config.

apps.vpn.naruzhuv2.5.0Chrome Web Store
45Risk

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

Publishers can request a review.

Findings

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-829
SourceAI SANDBOX

VPN proxy routing rules are fetched from a remote server with no integrity check

This VPN/proxy extension routes traffic through proxy servers.

On startup it fetches, with no integrity check, naruzhu.json, a PAC registry, then the PAC script, applied via chrome.proxy.settings.set.

Host/port also come from a remote API.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You install the extension and the background service worker starts.

No interaction beyond loading the extension is required; the configuration fetch fires automatically on service-worker startup.

The extension did this

The extension fetches its proxy routing rules from a remote server and applies them with no integrity check.

A three-stage fetch chain retrieves a PAC (Proxy Auto-Config) script whose URL is supplied by a remote registry, then applies it via chrome.proxy.settings.set to route browser traffic.

02EvidenceNETWORK CAPTURE
Captured request
GEThttps://storage.googleapis.com/uboost-neo/pca-scripts-registry-google.json
Returns a registry of PAC-script URLs. The selected URL (e.g. https://staticfiles.cukubst.top/pacs/free-pac-script.json) was then fetched and returned status 200, recorded in storage.session under apiHttpSuccess. Observed during dynamic analysis on service-worker startup, before any login.
03EvidenceTHIRD PARTY LIST
Remote sources that determine how your traffic is routed
  • storage.googleapis.com

    Hosts naruzhu.json (meta config) and the PAC-script registry uboost-neo/pca-scripts-registry-google.json. Google Cloud Storage bucket controlled by the extension operator.

  • storage.yandexcloud.net

    Fallback config host (vpnn-web-configs/...). Yandex Cloud Storage bucket used when the Google bucket path is selected as fallback.

  • staticfiles.cukubst.top

    Hosts the actual PAC script payload (pacs/free-pac-script.json) fetched in our session. Operator-controlled domain.

  • extension.nrz.homes

    apiBaseUrl returned by naruzhu.json; serves /api/v2/get-proxy, which returns the proxy host and port used to route traffic.

04EvidenceCODE COMPARE
The code that does this

The PAC-script URL comes from a remote registry; the decompressed script becomes the proxy config.

What it actually does
Stage 1: meta config endpoint selected and fetched as JSONbackground/service_worker.js
const path = devMeta ? 'naruzhu/naruzhu-test.json?version=3' : 'naruzhu/naruzhu.json';
const metaUrl = await resolveConfigBaseUrl(path);            // -> storage.googleapis.com or yandexcloud fallback
if (!metaUrl) throw new Error('No meta API URL provided');
const meta = await http.get(metaUrl.toString()).json();     // { apiBaseUrl, cookieDomain, ... } -- NO integrity check
Stage 2: PAC-script registry URL is server-selectable, fetched as JSONbackground/service_worker.js
const regName = devMeta ? 'uboost-neo/pca-scripts-registry-google-test.json'
                        : 'uboost-neo/pca-scripts-registry-google.json';
const regUrl = (configBase === 'https://storage.yandexcloud.net/vpnn-web-configs/')
  ? new URL(devMeta ? 'uboost-neo/pca-scripts-registry-yandex-test.json'
                    : 'uboost-neo/pca-scripts-registry-yandex.json', configBase)
  : new URL(regName, 'https://storage.googleapis.com/');
return await http.get(regUrl.toString()).json();            // registry -> per-tier PAC-script URLs
Stage 3 / apply: decompressed PAC string applied with no signature or SRIbackground/service_worker.js
const pac = buildPac({ host, port, pacString, shouldDecompress, vpnHost, vpnPort });
const proxyConfig = { mode: 'pac_script', pacScript: { data: pac } };
await chrome.proxy.settings.set({ value: proxyConfig, scope: 'regular' });
// No signature check, no Subresource Integrity, no pinned hash on any fetched file.
05EvidenceCODE COMPARE
The code that does this

Proxy host and port also come from the remote apiBaseUrl

What it actually does
async function getProxy({ apiBaseUrl, deviceId, deviceIp, onFail }) {
  const { featuresList } = await features.getSnapshotAsync();
  // apiBaseUrl itself came from the remote naruzhu.json config
  return await http.post(`https://${apiBaseUrl}/api/v2/get-proxy`, {
    json: { product: 'naruzhu', device_id: deviceId, device_ip: deviceIp ?? 'unknown', on_fail: onFail, with_auth: featuresList[Feature.ProxyAuth] }
  }).json();   // returns the proxy host/port that traffic is routed through
}
06EvidencePLAIN NOTE
What we did and did not observe

We observed the full remote configuration fetch chain (naruzhu.json -> PAC registry -> PAC script, status 200) fire on service-worker startup before any login. The final `chrome.proxy.settings.set` application step is gated behind an email one-time-password login wall that we did not pass in this session, so we did not observe traffic being actively re-routed. The remote-controlled, integrity-unchecked source of the routing rules — the substance of this finding — was fully demonstrated.

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-829
SourceAI SANDBOX

Remote config picks which domain the extension writes account cookies to

When userId or deviceId changes in local storage, the extension writes them as cookies to a domain read from remote config naruzhu.json.

Our test returned cuknrz.top; the extension set userId (login email) and deviceId cookies there.

01EvidenceCAUSE EFFECT
What actually happens
You did this

Your userId or deviceId changes in the extension's local storage.

A chrome.storage.onChanged listener watches for these identifier values changing.

The extension did this

The extension writes the identifier as a cookie to a domain it reads from a remote config file.

The destination is the cookieDomain field returned by storage.googleapis.com/naruzhu/naruzhu.json, not a hardcoded value in the extension.

02EvidenceNETWORK CAPTURE
Captured request
GEThttps://storage.googleapis.com/naruzhu/naruzhu.json
Response body observed during dynamic analysis: { apiBaseUrl: extension.nrz.homes, cookieDomain: cuknrz.top, currentVersion: 2.0.0, supportedBrowsers: [...], proxy: ... }. The cookieDomain value (cuknrz.top) is what the extension then wrote cookies to.
03EvidenceFIELD TABLE
Values written to the remote-config-supplied cookie domain (observed)
FieldValueWhy it matters
Account identifier (userId)
userId = <redacted>@example.comThe userId cookie carried the account identifier; in our session this was the email address entered at the login screen.
Device identifier (deviceId)
deviceId = 5f3c2a91-8b04-4e77-9c1a-2d6e0f4ab123A per-install device identifier, read and written to the same remote-config-supplied domain.
Destination domain (cookieDomain)
cuknrz.topThe domain cookies are written to, read from the remote naruzhu.json config, so a server change redirects where these identifiers are set.
04EvidenceCODE COMPARE
The code that does this

Cookie write/read target their URL at the remote-config cookieDomain

What it actually does
// cookieDomain is destructured from the remote meta config (naruzhu.json)
async function setIdentifierCookies(entries) {
  const { cookieDomain } = await getMetaConfig();        // <- remote-supplied
  for (const [name, value] of Object.entries(entries)) {
    await chrome.cookies.set({ url: `https://${cookieDomain}`, name, value, ...opts });
  }
}
async function getIdentifierCookie(name) {
  const { cookieDomain } = await getMetaConfig();        // <- remote-supplied
  const c = await chrome.cookies.get({ url: `https://${cookieDomain}`, name });
  return c ? { [name]: c.value } : { [name]: null };
}
05EvidenceCODE COMPARE
The code that does this

storage.onChanged listener triggers the cookie write when the identifier changes

What it actually does
chrome.storage.onChanged.addListener(changes => run(async () => {
  // identifier changes in storage.local are mirrored out to the cookieDomain
  // by setIdentifierCookies({ userId } / { deviceId }) on change.
  ...
}));

Data recipients

storage.googleapis.comstorage.yandexcloud.net
Updated 17 September 2026ekgejlkdmgojnobgegkcomigednijpnl