Is Display Email Time by cloudHQ safe?

Medium risk

Display Email Time by cloudHQ posts your Gmail account addresses to cloudHQ on each Gmail page load.

On Gmail pages the extension reads the active email address and fetches Gmail's account switcher for up to 20 account slots to collect the other addresses signed in. It then sends these addresses to cloudHQ's user check endpoint, and caches the result locally for about two weeks per address.

cloudHQv1.0.1.3Chrome Web Store
49Risk
Who publishes it

cloudHQ LLC - 19 other listings from the same operator, 7 of them carrying a finding

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

Publisher
cloudHQ
Declared legal entity
cloudHQ LLC
Registered address
2247 29th Ave, San Francisco, CA 94116-1738, US
Registered contact
cloudHQ LLC

Same store account

19 other listings published from this account, 183k+ users between them. 7 of them carry a finding.

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

Publishers can request a review.

Findings

Gmail extension sends all signed-in Gmail addresses to cloudHQ on each page load

Code analysis shows the extension reads every Gmail account in your account switcher and posts the addresses to cloudhq.net, at most about once every two weeks per address.

Severity
High unwanted
Type
Unexpected
CWE
CWE-359
Source
Static analysis
What actually happens
You did this

You open Gmail with several Google accounts signed in.

The extension did this

The extension collects every account address and posts the list to cloudhq.net.

No click or consent step precedes the request.

The code that does this

The pre-user check and the account-switcher enumeration

Readable version

Automatic call after initialisation

main_gmail_thread_list_time.js
})), N.fn_pre_user_check(), console.log("before fn_create_extension_toolbar"), N.fn_create_extension_toolbar(Y, (function(t) {

Account slot probe URL

main_gmail_thread_list_time.js
      fn_get_switcher_account_emails = function(e, t) {        var n = this;        if (n.g_switcher_account_emails_index > n.g_switcher_account_emails_max_tries) return n.g_email_or_login && -1 == n.g_switcher_account_emails.indexOf(n.g_email_or_login.toLowerCase()) && n.g_switcher_account_emails.push(n.g_email_or_login.toLowerCase()), void e();        try {          n.g_switcher_account_emails_index++;          var i = "https://mail.google.com/mail/u/" + n.g_switcher_account_emails_index + "/?sw=2";          t ? (i = t + n.g_switcher_account_emails_index + "/?tgif=d", r().ajax({            url: i,

Address extraction from the fetched page

main_gmail_thread_list_time.js
            mode: "cors"          }).then((e => e.text())).then((t => {            var r = /var GLOBALS=([\s\S]*?)\;/gm,              i = null;            try {              for (; i = r.exec(t);) {                var o = JSON.parse(JSON.stringify(i[1])).split(",");                if (o.length)                  for (var a = 0; a < o.length; a++)                    if (o[a] && n.fn_validate_email(o[a].replaceAll('"', ""))) {                      var s = o[a].replaceAll('"', "").toLowerCase();                      return n.g_switcher_account_emails && n.g_switcher_account_emails[0] && n.g_switcher_account_emails[0] == s ? (n.g_email_or_login && -1 == n.g_switcher_account_emails.indexOf(n.g_email_or_login.toLowerCase()) && n.g_switcher_account_emails.push(n.g_email_or_login.toLowerCase()), void e()) : (-1 == n.g_switcher_account_emails.indexOf(s) && n.g_switcher_account_emails.push(s), void n.fn_get_switcher_account_emails(e))                    }              }            } catch (e) {              console.log("fn_get_switcher_account_emails: failed e=", e)            }          })).catch((t => {            console.log("error in callback or not logged in to #" + n.g_switcher_account_emails_index + " account!"), n.fn_get_switcher_account_emails(e)          }))        } catch (e) {          console.log("fn_get_switcher_account_emails:error:", e)        }

POST to the vendor endpoint, gated by a two week cache

main_gmail_thread_list_time.js
      fn_pre_user_check = function(e) {        var t = this;        try {          var n = t.g_email_or_login + t.g_cloudHQ_feature_name + "_pre_check_obj",            r = ((new Date).getTime(), {              value: "true",              timestamp: (new Date).getTime()            }),            i = {};          i[n] = r, chrome.storage.local.get(n, (function(r) {            if (!r || !r[n] || !r[n].timestamp || r[n].timestamp < t.g_two_weeks_ago_timestamp) try {              t.fn_get_switcher_account_emails((function() {                t.fn_ajax({                  type: "POST",                  url: t.g_server_url + "main_pre_user/check",                  dataType: "json",                  data: {                    email: t.g_email_or_login,                    email_switcher_list: t.g_switcher_account_emails,                    email_or_login: t.g_email_or_login,                    chrome_extension_name: t.g_cloudHQ_feature_name,                    switch_login: "1"                  },                  complete: function(e, t) {                    if (-1 === ["error", "timeout", "abort"].indexOf(t)) try {                      chrome.storage.local.set(i, (function() {}))                    } catch (e) {}                  }                })              }), e)            } catch (e) {              console.log("e:", e)            }          }))        } catch (e) {          console.log("precheck failed e=", e)        }

Background relay allows only cloudhq.net URLs

background.js
    })), chrome.runtime.onMessage.addListener((function(e, t, n) {      if (e && "PROXY_AJAX" == e.what) {        var i = e.payload;        if (!i.url || !i.url.startsWith("https://www.cloudhq.net/")) return void n({          what: "error",          payload: "Invalid request"        });
Fields in the POST body to /main_pre_user/check
  • Active address
    jane.doe@gmail.com

    The Gmail address you are signed in as.

  • Other accounts
    ["jane.doe@gmail.com","j.doe@example.org"]

    Every other address found in your Gmail account switcher.

  • Feature name
    gmail_thread_list_time

    Which cloudHQ product sent the check.

  • Switch login flag
    1

    A fixed marker sent with the request.

Where the addresses go
    • www.cloudhq.net

    Vendor's own service; receives the active address and the account-switcher list.

    • mail.google.com

    Source of the addresses: /mail/u/N/?sw=2 is fetched for each account slot.

When this fires

On every browser startup

Runs on Gmail load; skipped while a stored timestamp for the address is under about two weeks old.

Observation

Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.

What it can do

Permissions this extension asks for, as declared in version 1.0.1.3. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.

  • Read and change your data on mail.google.com

    https://mail.google.com/

  • Read and change your data on mail-attachment.googleusercontent.com

    https://mail-attachment.googleusercontent.com/

  • Read and change your data on inbox.google.com

    https://inbox.google.com/

  • Read and change your data on www.cloudhq.net

    https://www.cloudhq.net/

  • Run its own code inside the pages you visit

    scripting

  • Store data in your browser

    storage

  • Keep running in the background while your browser is open

    background

  • See the address and title of every tab you have open

    tabs

Where it sends data

Destinations our analysis observed Email Time 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.

  • www.cloudhq.netwidely used

    Email Time sends data to www.cloudhq.net. A widely used service: 79 other extensions we have analysed send data here.

Updated 15 October 2026kedlbojealkpdllmgjeciofngjeokhno