Is tuBee safe?

High risk

tuBee automates YouTube likes, subscriptions, comments, and watch-status reporting through cityhire.net.

When you use its earning or boosting flow, tuBee opens server-selected YouTube watch pages and clicks subscribe and like controls, writes generated comments, and reports the completed actions. The reported data includes watched video IDs, watch time, and subscribe, like, and comment flags sent to cityhire.net/tubee/_ytsvr32.php.

sumagasoftv1.4.1Chrome Web Store
72Risk
Who publishes it

sumagasoft - no other listings under this identity, 2 shared hostnames

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

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

blogspot.com
Also called by 2 other listings, including New Tab Studio
3.bp.blogspot.com
Also called by 5 other listings, including Explain and Send Screenshots

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

Publishers can request a review.

Findings

tuBee automates YouTube actions and reports them

tuBee's Boost Video/Earn opens YouTube watch pages, clicks Subscribe and Like, and can post a comment, then sends the video ID, watch duration, and subscribe/like/comment/missing-video flags to https://cityhire.net/tubee/_ytsvr32.php.

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

You click tuBee's Boost Video or Earn control on a YouTube page.

The extension only reaches this workflow after that page-level action.

The extension did this

The extension opens YouTube watch pages, clicks engagement controls, and reports the result to cityhire.net.

The reported result includes which video was watched, how long it was watched, and whether Subscribe, Like, or comment actions ran.

Fields assembled for the WATCH_RESULT report
  • Boosted channel ID
    UC_x5XG1OV2P6uZZ5FSM9Ttw

    Connects the report to the channel involved in the boost workflow.

  • Boosted video ID
    dQw4w9WgXcQ

    Identifies the original YouTube video tied to the boost workflow.

  • Watched video ID
    9bZkp7q19f0

    Identifies the YouTube video the extension opened and watched for the earn workflow.

  • Watch duration
    120 seconds

    Shows how long the extension reports the watched video was played.

  • Subscribe flag
    1

    Shows whether the extension records that a Subscribe action was performed.

  • Like flag
    1

    Shows whether the extension records that a Like action was performed.

  • Comment flag
    1

    Shows whether the extension records that a generated comment was submitted.

  • Missing-video flag
    0

    Shows whether the extension reports that the target video could not be watched.

Captured request
POSThttps://cityhire.net/tubee/_ytsvr32.php

No response body was recorded with this claim.

Headers
Content-Type
application/x-www-form-urlencoded
The code that does this

The functions that automate engagement and report the result

Readable version

Readable equivalent of content.js engagement flow

content.js
function performYouTubeEngagement(shouldSubscribe, shouldLike) {  if (shouldSubscribe) {    waitAtRandomInterval(50000, 135000, () => {      const subscribeButton = findFirstElementByXPath("//*[(contains(@aria-label,'Subscribe to') or contains(@aria-label,'දායක වන්න'))]");      if (!subscribeButton) return false;      const wasAlreadySubscribed = alreadySubscribed();      subscribeButton.click();      performed_subscribe = !wasAlreadySubscribed;      update_SLC_status();      return true;    }, 60);  }  if (shouldLike) {    waitAtRandomInterval(8000, 50000, () => {      const likeButton = findFirstElementByXPath("//button[@aria-pressed='false' and contains(translate(@aria-label,'LIKE','like'),'like') and not(contains(translate(@aria-label,'DISLIKE','dislike'),'dislike')) and not(contains(translate(@aria-label,'UNLIKE','unlike'),'unlike'))]");      if (!likeButton) return false;      likeButton.click();      performed_like = true;      update_SLC_status();      return true;    }, 60);  }}function submitGeneratedYouTubeComment() {  waitAtRandomInterval(10000, 40000, () => {    const placeholder = document.querySelector("ytd-comments ytd-comment-simplebox-renderer div#placeholder-area");    if (!placeholder) return false;    placeholder.click();    const editor = findFirstElementByXPath("//*[@id='contenteditable-root' and (contains(@aria-label,'Add a comment') or contains(@aria-label,'Add a public') or contains(@aria-label,'අදහසක් එක් කරන්න'))]");    if (!editor || findNoOfPreviousComments() >= 1) return false;    editor.innerText = comment_generate(our_vid_comment_keywords.split(','));    const submitButton = findFirstElementByXPath("//*[@id='submit-button']");    if (!submitButton) return false;    submitButton.removeAttribute('disabled');    submitButton.removeAttribute('aria-disabled');    submitButton.click();    performed_comment = true;    update_SLC_status();    return true;  }, 60);}function earn() {  setProcessing_MainProcess(1);  chrome.runtime.sendMessage({ action: 'WatchVids' }, function(response) {});  document.getElementById('tblAccountHistory').setAttribute('hidden', true);}

Readable equivalent of background.js watch-tab coordination

background.js
function openMainTab(selectedVideoId, thumbnailUrl, selectedVideoTitle, selectedChannelId, selectedChannelName) {  ExtMainPageData = {    vidID: selectedVideoId,    imgUrl: thumbnailUrl,    VidTitle: selectedVideoTitle,    ChID: selectedChannelId,    ChName: selectedChannelName,  };  state_main.current_ch_id = selectedChannelId;  state_main.current_vid_id = selectedVideoId;  saveStates();  initOurVidsFromSvrOrStorage(() => {    getchVidRnd((watchVideoId, searchText, commentKeywords) => {      const watchUrl = 'https://www.youtube.com/watch?v=' + watchVideoId + url_param_byext_true;      chrome.tabs.create({ url: watchUrl, active: false }, (tab) => {        state_main.tab_id_ExtensionMain = tab.id;        saveStates();        chrome.storage.local.set({ key_caller_mode: 'extMain' }, function() {});        chrome.storage.local.set({ key_our_vid_comment_keywords: commentKeywords }, function() {});        if (tab.mutedInfo) chrome.tabs.update(tab.id, { muted: true });      });    });  });}function setupWatchTab(watchTabId) {  const watchVideo = {    vid_id: getTableValue(state_main.watchVidList, 'vid_id', state_main.curVidInd),    ch_id: getTableValue(state_main.watchVidList, 'ch_id', state_main.curVidInd),    watch_secs: getTableValue(state_main.watchVidList, 'watch_secs', state_main.curVidInd),  };  const timer = setInterval(() => {    getAdvRnd((adId, adUrl, thumbnailUrl, title, body) => {      const ad = { AdvID: adId, URL: adUrl, ThumbURL: thumbnailUrl, Title: title, Body: body };      if (watchVideo && watchVideo.vid_id && watchVideo.vid_id.length > 3) {        chrome.tabs.sendMessage(watchTabId, { action: 'setWatchVideoInfo', watchVideo, adv: ad }, (response) => {          if (response && response.suc === true) clearInterval(timer);        });      }    });  }, 3000);}

Readable equivalent of kandybridge.js result reporting

kandybridge.js
function reportWatchResult(originalVideo, watchedVideo, watchStatus, callback) {  const fields = [    'wby_ch_id', 'wby_vid_id', 'w_ch_id', 'w_vid_id', 'secs', 'sub', 'like', 'com', 'vid_mis'  ];  const row = [    originalVideo.ch_id,    originalVideo.vid_id,    watchedVideo.ch_id,    watchedVideo.vid_id,    watchStatus.wSeconds,    watchStatus.performed_subscribe ? '1' : '0',    watchStatus.performed_like ? '1' : '0',    watchStatus.performed_comment ? '1' : '0',    watchStatus.video_is_missing ? '1' : '0',  ];  const serializedData = SerializeObjectTableList(['[!]', '[~]', '[#]'], [[fields, ['', '', '', '', '', '', '', ''], row]], null);  postToServer(WebAddress_PHPExecuter(), 'WATCH_RESULT', 'cmd', serializedData, callback);}function postToServer(url, action, command, uploadData, callback) {  const body = 'pri=' + command + '&qac=' + action + '&pwd=' + 'edged5r4654sdfgv541873' + '&data=' + uploadData + '&';  const headers = new Headers();  headers.append('Access-Control-Allow-Origin', url);  headers.append('Content-Type', 'application/x-www-form-urlencoded');  fetch(url, { method: 'POST', headers, body })    .then((response) => response.text())    .then((data) => callback(data, ''))    .catch((err) => callback(err, 'NET_ACC_ERR'));}
External destination used by the reporting code
    • cityhire.net

    Receives tuBee WATCH_RESULT posts at /tubee/_ytsvr32.php, including watched video IDs, watch duration, and Subscribe, Like, comment, and missing-video flags.

Where it sends data

Destinations our analysis observed tuBee contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.

  • cityhire.net

    tuBee sends data to cityhire.net. No other extension we have analysed sends data here.

Updated 30 September 2026mpgcppooiieehfembbnljmjdhdnonjdc