Is Toby Mini safe?
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.
Who publishes itLaunch Labs INC - 2 other listings from the same operator, none carrying a finding
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.
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.
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
You start the AI suggestion flow for a Toby collection.
The collection UI labels the control as AI sorting or AI suggestions.
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.
- Saved card IDcard_7f6b2e91
Lets the returned suggestion refer back to a specific saved card in your collection.
- Saved page titleCompetitor pricing research
Shows the readable name or custom label for a saved page in your collection.
- Saved page domaindocs.example.com
Shows which website the saved page belongs to, even without the full address.
- Saved page URLhttps://docs.example.com/research/competitor-pricing
Reveals the exact saved page address from the selected collection.
The source expects a result object that maps suggested destination collection names or IDs to card ID arrays.
The collection-suggestion handler maps saved cards into a websites payload
Readable mutation payload inside NL
chunks/toby-USZ1T0Tx.jsconst 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.jsai: { 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 })}- 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
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 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.
- Tab identifier284
Lets the response map a suggested group back to the specific tab in your browser window.
- Open page URLhttps://docs.example.com/team/roadmap?quarter=Q3
Reveals the exact page address open in that tab, including path and query details when present.
- Page titleQ3 product roadmap - Team Docs
Shows readable context about the page even when the URL alone is not descriptive.
The source expects a result object whose keys become suggested tab-group names and whose values are tab ID lists.
The UI handler builds the tab list and the background API client posts it
Readable tab-list construction and mutation call
chunks/useSessionStart-lnsnpREA.jsconst 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.jsai: { 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 })}- 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.