Is Toby Mini safe?

Medium risk

Toby Mini sends open tab URLs and saved bookmark data to its servers when AI features are used.

When a user triggers the AI tab-grouping feature, Toby Mini collects the title and URL of every open, non-pinned tab and transmits that list to api2.gettoby.com. Similarly, the AI suggest-collections feature posts saved bookmark card URLs, titles, and domains to the same server. Both requests include the user's team ID and are only made on explicit user action.

Tobyv1.13.1Chrome Web Store
49Risk
Who publishes it

Launch Labs INC - 2 other listings from the same operator, none carrying a finding

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

Publisher
Toby
Declared legal entity
Launch Labs INC
Registered address
565 Great Northern Way #600, Vancouver, BC V5T 0H8, CA
Registered contact
Axiom Zen

Same store account

1 other listing published from this account, 300k+ users between them, none of them carrying a finding.

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.

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

api2.gettoby.com
Also called by 1 other listing
capi.gettoby.com
Also called by 1 other listing
favicons.gettoby.com
Also called by 1 other listing: Toby For Tabs
feedback.gettoby.com
Also called by 1 other listing: Toby For Tabs
gettoby.typeform.com
Also called by 1 other listing: Toby For Tabs
logs.gettoby.com
Also called by 1 other listing: Toby For Tabs
gettoby.com
Also called by 3 other listings
help.gettoby.com
Also called by 3 other listings

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

Publishers can request a review.

Findings

AI collection suggestions send saved URLs to Toby

Using Toby Mini's AI collection-suggestion feature takes saved cards from the collection and posts them to Toby's API.

The request has team/collection context plus a websites list with each card's ID, title, domain, URL.

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

You start the AI suggestion flow for a Toby collection.

The collection UI labels the control as AI sorting or AI suggestions.

The extension did this

The extension sends saved card details from that collection to Toby's API.

The submitted list includes saved page URLs, titles, domains, and card IDs.

Fields sent in the suggest-collections request
  • Saved card ID
    card_7f6b2e91

    Lets the returned suggestion refer back to a specific saved card in your collection.

  • Saved page title
    Competitor pricing research

    Shows the readable name or custom label for a saved page in your collection.

  • Saved page domain
    docs.example.com

    Shows which website the saved page belongs to, even without the full address.

  • Saved page URL
    https://docs.example.com/research/competitor-pricing

    Reveals the exact saved page address from the selected collection.

Captured request
POSThttps://api2.gettoby.com/v3/{teamID}/ai/suggest-collections

The source expects a result object that maps suggested destination collection names or IDs to card ID arrays.

The code that does this

The collection-suggestion handler maps saved cards into a websites payload

Readable version

Readable mutation payload inside NL

chunks/toby-USZ1T0Tx.js
const v = async A => {  try {    const k = await C.mutateAsync({        teamID: b,        collectionID: n.id,        websites: c[A].map(L => ({          id: L.id,          title: L.customTitle || L.title,          domain: L.domain,          url: L.url        }))      }),      R = [];    Object.entries(k.result).forEach(([L, P]) => {      const $ = P.map(B => n.cards.find(N => N.id === B)).filter(B => !!B);      if ($.length !== 0)        if ($C(L)) {          const B = i[L];          B && $.some(N => N.listId !== B.id) && R.push({            moveToList: B,            cards: $.filter(N => N.listId !== B.id)          })        } else {          const B = a.find(N => N.title === L);          B && $.some(N => N.listId !== B.id) ? R.push({            moveToList: B,            cards: $.filter(N => N.listId !== B.id)          }) : R.push({            newListName: L,            cards: $          })        }    }), R.sort(L => "newListName" in L ? 1 : -1), p(R), d(A), m(!1)  } catch (k) {    console.error(k)  }};

Readable background API methods

background.js
ai: {  generateListTitle: async ({    teamId: e,    collectionId: t,    config: n  }) => ge.post(`${e}/ai/collection-name`, {    collectionID: t  }, {    ...n,    baseURL: at.API_URL_V3  }),  feedback: async ({    teamId: e,    jobId: t,    config: n  }) => ge.patch(`${e}/ai/jobs`, {    jobID: t  }, {    ...n,    baseURL: at.API_URL_V3  }),  suggestCollections: async (e, t) => ge.post(`${e.teamID}/ai/suggest-collections`, e, {    baseURL: at.API_URL_V3,    ...t  }),  groupTabs: async (e, t) => ge.post(`${e.teamID}/ai/group-tabs`, e, {    baseURL: at.API_URL_V3,    ...t  })}
Network destination used by this feature
    • api2.gettoby.com

    Receives the AI suggest-collections POST containing the selected team and collection context plus saved card website records.

AI tab grouping sends open tab details to Toby

Clicking Toby Mini's AI tab-grouping control builds a list of open, non-pinned tabs in the window and posts it to Toby's API.

Each record has the tab's ID, title, and URL, so the server can suggest groups.

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

You click the Toby AI control to create a preview of grouped open tabs.

The UI text says it uses Toby AI to reorganize open tabs into categorized groups.

The extension did this

The extension sends the current window's non-pinned tab list to Toby's API.

Each record contains the browser tab ID, page title, and full URL.

Fields sent in the group-tabs request
  • Tab identifier
    284

    Lets the response map a suggested group back to the specific tab in your browser window.

  • Open page URL
    https://docs.example.com/team/roadmap?quarter=Q3

    Reveals the exact page address open in that tab, including path and query details when present.

  • Page title
    Q3 product roadmap - Team Docs

    Shows readable context about the page even when the URL alone is not descriptive.

Captured request
POSThttps://api2.gettoby.com/v3/{teamID}/ai/group-tabs

The source expects a result object whose keys become suggested tab-group names and whose values are tab ID lists.

The code that does this

The UI handler builds the tab list and the background API client posts it

Readable version

Readable tab-list construction and mutation call

chunks/useSessionStart-lnsnpREA.js
const d = async () => {  if (!(!n || !s)) {    f && y(null);    try {      const {        websites: c,        firstTobyTabId: x      } = s.reduce((S, C) => (!C.pinned && !getTabStates(C).tabToby && S.websites.push({        id: C.id?.toString() || "",        title: C.title || "",        url: C.url || ""      }), S.firstTobyTabId === void 0 && getTabStates(C).tabToby && (S.firstTobyTabId = C.id), S), {        websites: []      }), b = await o.mutateAsync({        teamID: n,        websites: c      }), E = [];      if (Object.entries(b.result).forEach(([S, C], T) => {          const A = s.filter(k => k.id && C.includes(k.id.toString()));          E.push({            title: S,            color: colorOptionsArr[T % colorOptionsArr.length],            tabs: A          })        }), !E.length) {        y("Unable to suggest tab groups, please try again");        return      }      u(E), wait(500).then(() => x ? chromeAPI.switchToTab(x) : openToby())    } catch (c) {      console.error("Error fetching tabs:", c)    }  }};

Readable background API methods

background.js
ai: {  generateListTitle: async ({    teamId: e,    collectionId: t,    config: n  }) => ge.post(`${e}/ai/collection-name`, {    collectionID: t  }, {    ...n,    baseURL: at.API_URL_V3  }),  feedback: async ({    teamId: e,    jobId: t,    config: n  }) => ge.patch(`${e}/ai/jobs`, {    jobID: t  }, {    ...n,    baseURL: at.API_URL_V3  }),  suggestCollections: async (e, t) => ge.post(`${e.teamID}/ai/suggest-collections`, e, {    baseURL: at.API_URL_V3,    ...t  }),  groupTabs: async (e, t) => ge.post(`${e.teamID}/ai/group-tabs`, e, {    baseURL: at.API_URL_V3,    ...t  })}
Network destination used by this feature
    • api2.gettoby.com

    Receives the AI group-tabs POST containing the selected team ID and the open-tab website list.

Where it sends data

Destinations our analysis observed Toby Mini 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.

  • api2.gettoby.com

    Toby Mini sends data to api2.gettoby.com. One other extension we have analysed sends data here.

Updated 30 September 2026gfdcgfhkelkdmglklfbndgopaihmoeci