Is Urban Browser Guard safe?

High risk

Urban Browser Guard is high risk. Using ChatGPT, Claude, Gemini, Grok, DeepSeek, Perplexity, Copilot, or Meta AI, this extension reads every message and reply, sending it to Urban VPN's guardrail.urban-vpn.com as 'Chats Anonymization', 10 KB per prompt, 30 KB per reply.…

Urban VPNv8.2.3Chrome Web Store
79Risk
Who publishes it

Urban Cyber Security INC - 3 other listings from the same operator, 3 of them carrying a finding

What this publisher told the store about itself, and the other listings that told it the same thing.

Publisher
Urban VPN
Declared legal entity
Urban Cyber Security INC
Registered address
1007 North Orange Street, 4th floor, Wilmington, DE 19801, US
Registered contact
Kfir Hod Moyal

Same store account

3 other listings published from this account, 7.1M+ users between them. 3 of them carry a finding.

Shared hosts - 5 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.

analytics-toolbar.urban-vpn.com
Also called by 3 other listings, including Urban Shield
config-toolbar.urban-vpn.com
Also called by 4 other listings, including Urban Shield
authentication.urban-vpn.com
Also called by 5 other listings, including Urban Shield
urban-vpn.com
Also called by 6 other listings, including Urban Shield, Social Bulk Downloader
api-pro.urban-vpn.com
Also called by 7 other listings, including Free VPN for Chrome

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

Publishers can request a review.

Findings

AI Chat Content Intercepted and Sent to Urban VPN Server

Using ChatGPT, Claude, Gemini, Grok, DeepSeek, Perplexity, Copilot, or Meta AI, this extension reads every message and reply, sending it to Urban VPN's guardrail.urban-vpn.com as 'Chats Anonymization', 10 KB per prompt, 30 KB per reply.

Severity
High unwanted
Type
Unexpected
CWE
CWE-359
Source
Dynamic sandbox
What actually happens
You did this

You type a message into ChatGPT, Claude, Gemini, or any of eight other AI chat platforms and send it.

The extension did this

The extension reads the text of your message, and the AI's reply, and transmits both to guardrail.urban-vpn.com.

This occurs in the background without any visible indicator. Both the outgoing prompt and incoming AI response are captured as separate requests.

Fields transmitted to guardrail.urban-vpn.com/rest/v1/pii/verify for each message
  • Message text
    Can you help me draft a resignation letter for my job at Acme Corp?

    The full text of what you typed or what the AI replied, up to 10 KB for your prompts and 30 KB for AI replies.

  • Persistent user key (ukey)
    a7f3b291-4e12-4d38-9c0e-8b2f1a3e5d72

    A permanent per-install identifier assigned at extension setup. Ties all your AI chat activity to a single profile across sessions.

  • Session ID (usession)
    3f8d2c1a-9b4e-47f6-a1d3-2e5c8b0f9a12

    A per-tab session token generated at page load, used to link multiple messages within a browsing session.

  • Conversation ID (rsession)
    conv_01ABCDEFghijklmnopqrstuv

    The platform's internal conversation identifier, links all messages within one AI chat thread.

  • Platform name (room)
    claude.ai

    Identifies which AI service you were using when the message was captured.

  • Message type
    user

    Whether the captured text is from you ('user') or the AI ('system').

The code that does this

The Claude.ai handler, one of nine platform-specific interceptors in sdk/resource.js

Readable version

Readable form: intercepts your Claude prompt and the AI reply

// Runs on claude.ai — intercepts every message you send to Claude.// CLD_COMMUNICATION_REGEX = /\/chat_conversations\/(?<sessionId>[^/]+)\/completion$/window.fetch = async function(...args) {  const [url, config] = args;  if (CLD_COMMUNICATION_REGEX.test(url) && config?.body) {    const conversationId = url.match(CLD_COMMUNICATION_REGEX)?.groups?.sessionId ?? "";    const userPrompt = JSON.parse(config.body).prompt ?? "";    if (userPrompt.trim()) {      // Send user prompt to Urban VPN server      communicator.sendMessage({        id: 'CHECK_PII',        data: {          text: userPrompt,        // your actual message text          usession: sessionToken,  // per-tab session ID          rsession: conversationId,// Claude conversation ID          room: 'claude.ai',          messageType: 'user'        }      });    }    // Then also reads and transmits the AI response from the SSE stream  }  return originalFetch.apply(this, args);};
Where AI chat content is transmitted
    • guardrail.urban-vpn.com

    Receives AI chat text for server-side PII detection, run by Urban VPN; /rest/v1/pii/verify accepts compressed JSON with message text, a user key, and conversation IDs.

Consent and activation

This behavior activates when users accept the 'Chats Anonymization' PII consent screen. The extension presents this as a privacy-enhancing feature that scans messages for personally identifiable information before transmission. The cloud-detection path sends text to guardrail.urban-vpn.com regardless of whether any PII is found; the server's response indicates detected PII positions, which the extension then highlights in the UI. Device-side detection runs locally without this network call, but the cloud path is enabled alongside it when consent is accepted.

Full Browsing URL, Title, and Referrer Sent to Urban VPN on Each Navigation

With safe-browsing active, every navigation sends the URL, title, and referrer to anti-mining-protection-toolbar.urban-vpn.com, plus a persistent ID.

A server filter can suppress sensitive URLs; otherwise sent every time, once accepted.

Severity
High unwanted
Type
Unexpected
CWE
CWE-359
Source
Dynamic sandbox
What actually happens
You did this

You navigate to any web page when the extension's safe-browsing feature is enabled.

The extension did this

The extension sends the page URL, title, and the URL you came from to anti-mining-protection-toolbar.urban-vpn.com together with a persistent per-user identifier.

The payload is LZ-compressed and posted as application/octet-stream. A server-synced sensitive-URL filter may suppress the request for matching URLs, but the URL is sent for all other navigations.

Fields sent to anti-mining-protection-toolbar.urban-vpn.com on every navigation
  • Page URL
    https://mail.google.com/mail/u/0/#inbox/FMfcgzQXJvzRBmKlpNsPqWvHrdTkLpXy

    The full URL of every page you navigate to, including query parameters and fragments.

  • Referrer URL
    https://www.google.com/search?q=urban+vpn+review

    The URL of the page you came from. Combined with the current URL, this reconstructs your browsing path.

  • Page title
    Inbox (3) - james@example.com - Gmail

    The title of the page you just visited, as it appears in the browser tab.

  • Persistent user ID (panalyticsId)
    c8d3f2a1-5e74-4b9c-a012-1f3e7b2d4c6a

    A permanent identifier unique to your install. Lets the server tie every URL submission to a single user profile.

  • OS name and version
    Windows 11

    Your operating system and version number, sent with every request.

The code that does this

Payload assembly in FgNavProcessor (service-worker/index.js:26328)

Readable version

Readable form: navigation payload builder

// Called on every webNavigation.onCompleted event.async function processNavigation(navEvent) {  const payload = builder    .withUrl(navEvent.url)                         // full page URL    .withTimestamp(navEvent.timestamp)    .withOS(env.getOS().name, env.getOS().version) // OS info    .withPanelistDef(      options.panalyticsId,   // persistent per-user ID      options.pinstanceId,      options.partnerId,      // hardcoded '10'      options.distributorId   // hardcoded '10'    )    .withPageAttributes(      navEvent.pageData.title,    // page title      navEvent.pageData.name    )    .withContextAttributes(navEvent.pageData.referrer); // referring URL  await checkSafetyService.check(navEvent.tabId, payload);  // → POSTs compressed payload to /secure/urls/checkSafety}
Where browsing data is transmitted
    • anti-mining-protection-toolbar.urban-vpn.com

    Receives the URL, title, referrer, and user ID per navigation. Operated by Urban VPN; /secure/urls/checkSafety returns a verdict used by the URL-blocking feature.

    • authentication.urban-vpn.com

    Provides the server-side sensitive-URL rules list, synchronized every 360 minutes. URLs matching these rules are excluded from the checkSafety call.

Numeric-Named Executors Intercept Social Media Traffic via Remote Config

Scripts 301.js-308.js inject into Facebook, X, TikTok, Instagram, LinkedIn, Pinterest, Reddit, Twitch, YouTube, patching fetch/XHR for ad/video data.

URLs come from sessionStorage key bis_data. v8.1.0 renamed names to opaque numbers.

Severity
High unwanted
Type
Unexpected
CWE
CWE-506
Source
Dynamic sandbox
What actually happens
You did this

You visit a social media or video platform where the extension is active.

The extension did this

A numbered executor script is injected into the page and replaces the browser's network request functions to observe API responses matching server-configured URL patterns.

The intercepted data, ad video metadata, carousel content, sponsored post structure, is relayed to the extension's background via window.postMessage and then chrome.runtime.sendMessage. The specific URL patterns to intercept are not fixed in the extension; they are fetched from bis_data in sessionStorage, which is populated from a remote server.

The code that does this

Version 8.1.0 replaced descriptive executor filenames with numeric identifiers

Readable version

Readable form: URL patterns come from remote server config, not hardcoded in extension

// Configuration loaded from bis_data sessionStorage key (server-populated)// g.videoDetectorConfigNew.MATCH_URLS defines which API response URLs to intercept.// These URLs are NOT in the extension source — they come from the remote server.const MATCH_URLS = remoteConfig.videoDetectorConfigNew.MATCH_URLS; // e.g. ['api/graphql', '/videos/mute']const MATCH_HEADERS = remoteConfig.videoDetectorConfigNew.MATCH_HEADERS;// All XHR responses are checked against server-supplied URL patterns:XMLHttpRequest.prototype.send = function(body) {  const originalHandler = this.onreadystatechange;  this.onreadystatechange = function() {    if (this.readyState === 4) {      const matchesUrl = MATCH_URLS.some(pattern => this.responseURL.includes(pattern));      if (matchesUrl) {        // Extract ad/video metadata and relay internally        window.postMessage({ type: '301_VIDEO_DATA', content: parsedData }, '*');      }    }    if (originalHandler) originalHandler.apply(this, arguments);  };  originalSend.apply(this, [body]);};
Platforms where executor scripts run
    • facebook.com

    executor/301.js intercepts GraphQL and video API responses to extract sponsored post and video metadata.

    • twitter.com / x.com

    executor/302.js intercepts timeline API responses.

    • tiktok.com

    executor/303.js intercepts video feed API responses.

    • pinterest.com

    executor/304.js and 304j.js intercept feed and pin data, including __PWS_INITIAL_PROPS__ page state.

    • instagram.com

    executor/305.js intercepts story, reel, and carousel data.

    • linkedin.com

    executor/306.js intercepts feed post responses.

    • reddit.com

    executor/307.js intercepts post listing responses.

    • twitch.tv

    executor/308.js intercepts video stream candidate data.

Remote-extensible scope

The URL patterns that each executor intercepts are not fixed in the extension code. They are delivered in the server-provided 'bis_data' configuration, which is populated into sessionStorage before the executor runs. This means the set of API endpoints observed on each social platform can be changed by the server operator without an extension update. The numeric filename scheme (301–308) replaced descriptive names (facebook.js, twitter.js, etc.) in version 8.1.0, removing the per-platform labelling that made the interception scope visible in earlier versions.

Updated 30 September 2026almalgbpmcfpdaopimbdchdliminoign