Is 셀러라이프 safe?
셀러라이프 is high risk. When you select text on a page or in a field and click translate, the extension sends it to sellerlife.co.kr with a persistent UUID header and an encrypted header repeating the UUID, extension ID, and first ten characters of the text.
Who publishes it주식회사 - no other listings under this identity, 4 shared hostnames
주식회사 - no other listings under this identity, 4 shared hostnames
What this publisher told the store about itself, and the other listings that told it the same thing.
Shared hosts - 4 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
Selected text sent to sellerlife.co.kr with persistent ID
When you select text on a page or in a field and click translate, the extension sends it to sellerlife.co.kr with a persistent UUID header and an encrypted header repeating the UUID, extension ID, and first ten characters of the text.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Dynamic sandbox
You select text on a webpage or inside a text field and click the translation control.
The control is injected on every matched page by the extension content script.
The extension sends that selected text to sellerlife.co.kr with a persistent extension UUID.
The request also carries an encrypted header containing the extension ID, UUID, and the first ten characters of the selected text.
- Selected textwireless keyboard replacement policy
The words you highlighted are sent for translation. If you highlight sensitive page or form text, that selected text is included.
- Source languageko
The request can include the language the extension is translating from.
- Target languageen
The request can include the language the extension is translating into.
- Persistent extension ID9b24c2b1-49ad-46cf-86c0-b8a0df8f82c4
A UUID kept by the extension can link separate translation requests from the same browser install.
- Encrypted request header{"eid":"cgococegfcmmfcjggpgelfbjkkncclkf","uuid":"9b24c2b1-49ad-46cf-86c0-b8a0df8f82c4","so":"wireless k"}
The encrypted header repeats the persistent ID and includes the first part of the selected text.
The static proof path expects a JSON response consumed by then(e => e.json()). Observed traffic did not include this POST; only extension-domain GETs to sellochomes.co.kr were observed when the translation click path was not exercised.
Content-script selection capture and iframe handoff
Manifest injects the translation content script on all URLs
manifest.json{ "js": ["translate/translate.js"], "matches": ["<all_urls>"], "run_at": "document_end", "all_frames": true }Clicking the translation control posts the selected text to the iframe
translate/translate.jsif (!!n.target.closest(".sellerlife-translate-btn") || !!n.target.closest(".sellerlife-translate-btn-text") || "s-translate-icon" === n.target?.id) { n.preventDefault(), n.stopPropagation(), d.style.display = "none", a.classList.remove("menu-open"); const e = r.getAttribute("text"); if (!e) return; await k(); const t = 12, o = 650, i = 414, c = a.getBoundingClientRect(), u = { left: c.left + window.scrollX + T(), top: c.top + window.scrollY + R() }, p = w || { left: u.left, top: u.top, right: u.left + 35, bottom: u.top + 35 }, m = (document.documentElement.clientWidth || window.innerWidth) + window.scrollX + T(), f = (document.documentElement.clientHeight || window.innerHeight) + window.scrollY + R(); let y = p.right + 10, g = p.top; y + o + t > m && (y = p.left - o - 10, y < window.scrollX + T() + t && (y = window.scrollX + T() + t)), g + i + t > f && (g = f - i - t), g < window.scrollY + R() + t && (g = window.scrollY + R() + t), s.style.left = `${y}px`, s.style.top = `${g}px`, s.style.display = "block", l = !0, N(), await async function(e) { await k(), s?.contentWindow && s.contentWindow.postMessage({ type: "s-translate-select-open", text: e }, "*") }(e) } }))) }Mouseup handler reads input-field selections and page selections
translate/translate.jsfunction Y(e) { if (!n) return; if (m && !f && !d(e.target)) return P(), H(), B(), A(), w = null, y = null, $(), m = !1, void(f = !1); const t = 12, o = window.scrollX, i = window.scrollY, s = document.documentElement.clientWidth || window.innerWidth, a = document.documentElement.clientHeight || window.innerHeight; L = o, x = i; const c = document.activeElement; if (c && ("INPUT" === c.tagName || "TEXTAREA" === c.tagName)) { const n = function(e) { if (!e || !("selectionStart" in e) || !("selectionEnd" in e)) return ""; const { selectionStart: t, selectionEnd: n, value: o } = e; return null == t || null == n || t === n ? "" : (o || "").substring(t, n) }(c).trim(); if (!n) return d(e.target) || (P(), H(), B(), A()), w = null, y = null, $(), m = !1, void(f = !1); l = !1, V(); const u = I(c), C = { left: u.left - o - T(), top: u.top - i - R(), right: u.right - o - T(), bottom: u.bottom - i - R() }, L = r.offsetWidth || 25, x = r.offsetHeight || 25, S = _(c); let W, N; if (g = S ? "fixed" : "doc", "fixed" === g) r.style.position = "fixed", W = C.right + 8, N = C.bottom + 8, W + L + t > s && (W = C.left - 8 - L), N + x + t > a && (N = a - x - t), W < t && (W = t), N < t && (N = t); else { r.style.position = "absolute", W = u.right + 8, N = u.bottom + 8; const e = s + o + T(), n = a + i + R(); W + L + t > e && (W = u.left - 8 - L), N + x + t > n && (N = n - x - t), W < o + T() + t && (W = o + T() + t), N < i + R() + t && (N = i + R() + t) } return r.style.left = `${W}px`, r.style.top = `${N}px`, r.style.display = "block", p(), r.setAttribute("text", n), w = { ...u }, y = "input", v = null, h = null, b = c, E = c.selectionEnd ?? null, M(c), l = !1, k(), V(), m = !1, void(f = !1) } const u = window.getSelection(); if (!u || u.isCollapsed || !u.rangeCount) return d(e.target) || (P(), H(), B(), A()), w = null, y = null, $(), m = !1, void(f = !1); const C = u.toString().trim(); if (!C) return P(), H(), B(), A(), w = null, y = null, $(), m = !1, void(f = !1); l = !1, k(), V(); const S = u.getRangeAt(0), W = S.getClientRects?.(), N = W && W.length ? W[W.length - 1] : (() => { const e = S.cloneRange(); return e.collapse(!1), e.getBoundingClientRect() })(), X = { left: N.left + o + T(), top: N.top + i + R(), right: N.right + o + T(), bottom: N.bottom + i + R() }, z = r.offsetWidth || 25, D = r.offsetHeight || 25, Y = 1 === S.endContainer.nodeType ? S.endContainer : S.endContainer.parentElement, O = _(Y); let U, F; if (g = O ? "fixed" : "doc", "fixed" === g) r.style.position = "fixed", U = N.right + 8, F = N.bottom + 8, U + z + t > s && (U = N.left - 8 - z), F + D + t > a && (F = a - D - t), U < t && (U = t), F < t && (F = t); else { r.style.position = "absolute"; const e = s + o + T(), n = a + i + R(); U = X.right + 8, F = X.bottom + 8, U + z + t > e && (U = X.left - 8 - z), F + D + t > n && (F = n - D - t), U < o + T() + t && (U = o + T() + t), F < i + R() + t && (F = i + R() + t) } r.style.left = `${U}px`, r.style.top = `${F}px`, r.style.display = "block", p(), r.setAttribute("text", C), w = { ...X }, y = "content", v = S.cloneRange(), h = Y, b = null, E = null, M(Y), m = !1, f = !1 }Translation iframe builds the sellerlife.co.kr POST
Request builder and POST
translate/translate-sl.jsasync function a(e, t = void 0, o = void 0) { if (null == (e = e.trim()) || "" == e) return; if (r.source == t && r.target == o && r.text == e) return r; let c; c = null == t || null == o ? { text: e } : { text: e, source: t, target: o }; let a = { eid: chrome.runtime.id, uuid: n(), so: e.slice(0, 10) }, s = new JSEncrypt; s.setKey(function(e) { for (var t = [], r = 0; r < e.length; r += 2) t.push(parseInt(e.substr(r, 2), 16)); return decodeURIComponent(escape(String.fromCharCode.apply(null, t))) }("2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0d0a4d4947664d413047435371475349623344514542415155414134474e4144434269514b426751436c6b6d336931694a6b53596e68546f656f6535312b674e4c670d0a686a412f47364d32767570372b6764392f6d566f4f347a4c6f2f313179794d68736678416e62514a37582f64616e704667375159614943487a786c41576259410d0a79356233674d2b35784641464b5241623859646b2b305a38367a463147515774543363383934345157663469584e2f63566857317932584a38466d3151614a6c0d0a3351364f4f7a36336c4d635368786f3936514944415141420d0a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d")); let l = s.encrypt(JSON.stringify(a)); return fetch("https://sellerlife.co.kr/pc/chrome-extension", { method: "POST", mode: "cors", cache: "no-cache", credentials: "include", headers: { "Content-Type": "application/json", uuid: n(), et: l }, referrerPolicy: "no-referrer", body: JSON.stringify(c) }).then((e => e.json())).then((t => { if (t.hasOwnProperty("error")) throw "1" != t.error && alert(t.error), new Error(t.error); return Object.prototype.hasOwnProperty.call(t, "source") && (r.source = t.source), Object.prototype.hasOwnProperty.call(t, "target") && (r.target = t.target), Object.prototype.hasOwnProperty.call(t, "translatedText") && (r.text = e, r.translatedText = t.translatedText), t })).catch((e => {}))}Persistent UUID helper
translate/translate-sl.jsfunction n() { return null == localStorage.getItem("uuid") && localStorage.setItem("uuid", self.crypto.randomUUID()), localStorage.getItem("uuid")}- sellerlife.co.kr
Receives the translation POST containing selected text and the persistent extension UUID headers.