Is EverBee - Find Best Selling Products on Etsy safe?
EverBee is low risk. When EverBee's AI image feature is activated, a content script sends the image URL, rectangle, title, and page URL to the background, which fetches or crops the tab, stores it behind a token, then opens an AI provider to retrieve it.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
EverBee AI hands page images to AI provider tabs
When EverBee's AI image feature is activated, a content script sends the image URL, rectangle, title, and page URL to the background, which fetches or crops the tab, stores it behind a token, then opens an AI provider to retrieve it.
- Severity
- Low unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Dynamic sandbox
You activate EverBee's AI image tool on a page image.
The code only shows the control when the image is at least 80 by 80 pixels and the EverBee session and feature setting are present.
The extension prepares the image and opens an AI provider tab that can retrieve it.
If direct image fetching fails, the background captures the visible tab and crops it to the image rectangle.
- Image URLhttps://upload.wikimedia.org/wikipedia/commons/3/3a/Cat03.jpg
The extension can fetch the exact image you selected from the page.
- Image rectangleleft 146, top 214, width 640, height 427
The extension knows where the selected image appears on your screen so it can crop the visible tab if fetching fails.
- Page title and addressCat - Wikipedia https://en.wikipedia.org/wiki/Cat
The extension sends the current page title and address to its background code along with the image request.
- Provider choicegemini
The extension chooses which AI provider tab will receive the prompt and image handoff.
- Image token1720811234567-k4m9q2n8p1
The provider-page script uses this temporary token to retrieve the pending image from the extension.
Provider-page navigation constructed by the extension; no request body was recorded.
Code path that collects the image and hands it to the provider tab
Content script sends the selected image to the background
gemini/content.jsself.EverBeeAI?.Menu?.init({ onRun: async function({ action: e, prompt: t, image: n, settings: o }) { try { console.log("[EverBee AI][cs] dispatch CAPTURE_AND_OPEN", { imageUrl: n.src, hasRect: Boolean(n.rect), host: location.host }); const r = await chrome.runtime.sendMessage({ type: "CAPTURE_AND_OPEN", prompt: t, imageUrl: n.src, rect: n.rect, dpr: window.devicePixelRatio || 1, pageContext: `${document.title}\n${location.href}`, provider: e.provider || o.defaultProvider, model: e.model || o.defaultModel }); console.log("[EverBee AI][cs] CAPTURE_AND_OPEN response", r) } catch (e) { throw console.warn("[EverBee AI] run failed", e), e } }});Background stores the image and builds provider URLs
backgroundScripts/background.jsconst pendingImages = new Map;function buildProviderUrl(e, t, r, o = "") { const a = resolveProviderBase(e), n = new URL(a); return n.searchParams.set("ext_prompt", t || ""), n.searchParams.set("ext_source", r || "paragraph"), o && n.searchParams.set("ext_img_token", o), n.toString()}function resolveProviderBase(e) { switch ((e || "").toLowerCase()) { case "chatgpt": case "gpt": case "openai": return "https://chatgpt.com/"; case "claude": case "anthropic": return "https://claude.ai/new"; default: return "https://gemini.google.com/" }}function setPendingImage(e) { const t = `${Date.now()}-${Math.random().toString(36).slice(2)}`; return pendingImages.set(t, { dataUrl: e, createdAt: Date.now() }), cleanupPendingImages(), t}function cleanupPendingImages() { const e = Date.now(); for (const [t, r] of pendingImages.entries()) e - r.createdAt > 12e4 && pendingImages.delete(t)}Background fetches or screenshots the image, then opens the provider
backgroundScripts/background.jsif ("CAPTURE_AND_OPEN" === e.type) return (async () => { try { const o = "string" == typeof e.prompt ? e.prompt : "", a = e.imageUrl ? "image" : "paragraph"; let n = ""; if (console.log("[EverBee AI][bg] CAPTURE_AND_OPEN received", { hasImageUrl: Boolean(e.imageUrl), imageUrl: e.imageUrl, rect: e.rect, dpr: e.dpr, source: a, provider: e.provider }), "image" === a) { let s = null, c = "none"; if (e.imageUrl) try { console.log("[EverBee AI][bg] fetching image URL (strict)", e.imageUrl), s = await fetchHttpImageAsDataUrl(e.imageUrl), c = "strict-fetch", console.log("[EverBee AI][bg] strict fetch OK, dataUrl length =", s.length) } catch (t) { console.warn("[EverBee AI][bg] strict fetch failed, retrying without CORS opts", t); try { const t = await fetch(e.imageUrl); if (console.log("[EverBee AI][bg] retry fetch status", t.status, t.type), t.ok) { const e = await t.blob(); if (e.type && e.type.startsWith("image/")) { const t = await e.arrayBuffer(), r = new Uint8Array(t); let o = ""; for (let e = 0; e < r.length; e += 8192) o += String.fromCharCode(...r.subarray(e, e + 8192)); s = "data:" + e.type + ";base64," + btoa(o), c = "retry-fetch", console.log("[EverBee AI][bg] retry fetch OK, dataUrl length =", s.length) } else console.warn("[EverBee AI][bg] retry fetch returned non-image blob", e.type) } } catch (e) { console.warn("[EverBee AI][bg] all direct image fetches failed, using screenshot fallback", e) } } if (!s && e.rect && e.dpr) return console.warn("[EverBee AI][bg] falling back to screenshot capture"), void chrome.tabs.captureVisibleTab(t.tab.windowId, { format: "png" }, (async t => { if (!chrome.runtime.lastError && t) try { const s = await cropToDataUrl(t, e.rect, e.dpr); n = setPendingImage(s), chrome.tabs.create({ active: !1, url: buildProviderUrl(e.provider, o, a, n) }), r({ ok: !0, via: "screenshot" }) } catch (e) { r({ ok: !1, error: e.message }) } else r({ ok: !1, error: chrome.runtime.lastError?.message || "Capture failed" }) })); s && (n = setPendingImage(s), console.log("[EverBee AI][bg] using fetched image, strategy =", c)) } chrome.tabs.create({ active: !1, url: buildProviderUrl(e.provider, o, a, n) }), r({ ok: !0 }) } catch (e) { r({ ok: !1, error: e?.message || "Failed to open Gemini" }) }})(), !0;Provider page retrieves the pending image by token
gemini/gemini.jsasync function getPendingPrompt() { const e = new URLSearchParams(window.location.search), t = (e.get("ext_prompt") || "").trim(), n = (e.get("ext_source") || "paragraph").trim(), a = (e.get("ext_img_token") || "").trim(); if (t) return clearExtQueryParams(), { prompt: t, source: n, imageToken: a, timestamp: Date.now() }; try { const e = await chrome.storage.session.get("gemini_pending"), t = e?.gemini_pending; return t ? Date.now() - t.timestamp > 3e4 ? (chrome.storage.session.remove("gemini_pending"), null) : (chrome.storage.session.remove("gemini_pending"), t) : null } catch (e) { return console.warn("[Gemini Ext] storage.session unavailable:", e), null }}async function getPendingImageDataUrl(e) { if (!e) return null; try { const t = await chrome.runtime.sendMessage({ type: "GET_PENDING_IMAGE", token: e }); return t?.ok && t.dataUrl ? t.dataUrl : null } catch (e) { return console.warn("[Gemini Ext] Unable to fetch pending image:", e), null }}- gemini.google.com
Default provider page opened with ext_prompt, ext_source, and ext_img_token query parameters.
- chatgpt.com
OpenAI provider page selected by the extension when the provider is ChatGPT, GPT, or OpenAI.
- chat.openai.com
Alternate ChatGPT host where the extension injects its provider-page image attachment script.
- claude.ai
Anthropic provider page selected by the extension when the provider is Claude or Anthropic.