Is Google Meet Translation and AI Note Taker safe?

High risk

JotMe is high risk. We observed the extension send popup metrics to api.jotme.io when the popup opened. The request included the active tab URL and a list of other open tab URLs, including pages outside Google Meet such as chrome://extensions/ and about:blank.

JotMev3.23.0Chrome Web Store
72Risk
Who publishes it

Jotme Limited - 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
JotMe
Declared legal entity
Jotme Limited
Registered address
124 City Road, London EC1V 2NX, GB
Registered contact
JOTME LIMITED

Same store account

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

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

Publishers can request a review.

Findings

Open tab URLs sent to JotMe when the popup opens

We observed the extension send popup metrics to api.jotme.io when the popup opened.

The request included the active tab URL and a list of other open tab URLs, including pages outside Google Meet such as chrome://extensions/ and about:blank.

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

You open the extension popup or start a new chat from the popup.

The extension did this

The extension sends a metrics event containing the active tab URL and other open tab URLs to JotMe.

Captured request
POSThttps://api.jotme.io/jotme/popup/metrics

Dynamic analysis captured two outbound POST requests; the server returned 400 because the bearer token was not accepted.

Headers
Authorization
Bearer <redacted>
Fields observed in the popup metrics request
  • Active tab URL
    https://app.jotme.io/

    Shows the page you had active when the popup event was created.

  • Other open tabs
    chrome://extensions/

    Shows additional pages open in the browser at the same time, even when they are not Google Meet pages.

  • Another open tab
    about:blank

    Adds more browsing context from the same browser session.

  • Popup event type
    Open

    Shows whether the event came from opening the popup, closing it, or starting a new chat.

  • Extension access token
    Bearer <redacted>

    Ties the metrics request to the signed-in extension session.

The code that does this

Popup metrics message and service-worker tab enumeration

Readable version

Popup helper sends popupMetrics messages

popup/assets/index-CNQREzUr.js
class Rm {}Cr(Rm, "send", o => {  const c = WO.safeParse(o);  if (!c.success) return;  const d = {    message: "popupMetrics",    ...c.data  };  chrome.runtime.sendMessage(d)});

Popup Open and NewChat call sites

popup/assets/index-CNQREzUr.js
    C(""), ye(!1), Ht(l[d].translate.languageDetection.placeholder), fe(!1), Ue(""), ft("");    const Ne = jS();    Xt(Ne), (Ye = At.current) == null || Ye.focus(), Rm.send({      chatSessionId: Ne,      type: "NewChat"    })        Xt(oe), C(be.popup.chatInput ?? ""), Kt(Z), F(((vt = be.popup.explain) == null ? void 0 : vt.chats) ?? []), y(((Dt = be.popup.translate) == null ? void 0 : Dt.targetLanguage) ?? "en"), console.log("popup chats ", (Ge = be.popup.translate) == null ? void 0 : Ge.chats), B(((rt = be.popup.translate) == null ? void 0 : rt.chats) ?? []), Ue(((It = be.popup.translate) == null ? void 0 : It.translateSource) ?? ""), ft(((Rn = be.popup.translate) == null ? void 0 : Rn.translateContext) ?? ""), Ht(((ua = be.popup.translate) == null ? void 0 : ua.sourceLanguage) ?? ""), Rm.send({          chatSessionId: oe,          type: "Open"        })

Service worker handles popupMetrics and posts the request

service-worker.js
        s = e => {          const {            message: o          } = e, t = r(e, ["message"]);          n(void 0, void 0, void 0, (function*() {            var e;            if ("popupMetrics" !== o) return;            const n = yield chrome.tabs.query({              active: !0,              currentWindow: !0            }), r = (yield chrome.tabs.query({})).filter((e => {              var o;              return (null == e ? void 0 : e.id) !== (null === (o = null == n ? void 0 : n[0]) || void 0 === o ? void 0 : o.id)            }));            if ("Close" !== t.type) {              const o = {                activeTabHref: null === (e = null == n ? void 0 : n[0]) || void 0 === e ? void 0 : e.url,                otherTabs: r.map((e => null == e ? void 0 : e.url)).filter((e => void 0 !== e)).map((e => ({                  href: e                })))              };              t.activeTabURL = o.activeTabHref, t.otherTabs = o.otherTabs            }            const i = (yield chrome.storage.local.get("access")).access;            if ("" === t.chatSessionId) {              const e = yield chrome.storage.local.get("popup");              t.chatSessionId = e.popup.sessionId            }            fetch("https://api.jotme.io/jotme/popup/metrics", {              method: "POST",              body: JSON.stringify(t),              headers: {                Authorization: `Bearer ${i}`              }            })          }))        },
Destination receiving the tab snapshot
    • api.jotme.io

    Receives popup metrics events containing the active tab URL and other open tab URLs.

Updated 30 September 2026dblnhakdbdnbpijekdfofikccmgpebno