Is EasyPubMedicine safe?
EP is medium risk. EasyPubMedicine has a sidebar-controlled clipboard listener. Once started, the background script picks a sandbox textarea, runs Chrome's paste command each second, reads paste-event text, strips control chars, returns it via the port.…
Who publishes itEasyPubMed - no other listings under this identity, 2 shared hostnames
EasyPubMed - no other listings under this identity, 2 shared hostnames
What this publisher told the store about itself, and the other listings that told it the same thing.
Shared hosts - 2 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
Sidebar clipboard listener polls text every second
EasyPubMedicine has a sidebar-controlled clipboard listener.
Once started, the background script picks a sandbox textarea, runs Chrome's paste command each second, reads paste-event text, strips control chars, returns it via the port.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-200
- Source
- Dynamic sandbox
You use the sidebar path that starts clipboard listening.
The extension checks for clipboard text every second and returns changed text through its own port.
The confirmed source path is gated behind the sidebar-controlled listener rather than running on every page load.
Every 1 second
After the listener starts, the background script repeats the paste check once per second until disabled.
- Clipboard textPMID 30293440 abstract note copied for translation
Text you copied can be read by the extension while this listener is active.
- Sanitized textTrial design summary copied from a PubMed page
Line breaks and a control character are removed before the text is sent through the extension port.
Background clipboard polling path
Readable background method
js/background.jsasync watchClipboard() { let e = this; function t() { document.getElementById("sandbox").select(), document.execCommand("paste") } window.ep.watchClipboardIntervalId && clearInterval(window.ep.watchClipboardIntervalId), Et("#sandbox").length || Et("body").append("<textarea id='sandbox'></textarea>"), window.ep.watchClipboardIntervalId = setInterval(t, 1e3); let n = !0; this.pasteListener = function(t) { t.preventDefault(); let r = t.clipboardData.getData("text"); if (n) return n = !1, void(window.ep.clipboard = r); window.ep.clipboard != r && (window.ep.clipboard = r, e.responseMessage({ clipboard: r.replace(/[\r\n\x02]/g, "") }, { msg: "clipboardResponse", ori: !1 })) }, document.addEventListener("paste", this.pasteListener)}Sidebar screenshot feature captures the active tab
EasyPubMedicine's screenshot feature attaches Chrome's debugger API to the tab for a full-page PNG.
The script builds a bounding box, requests Page.captureScreenshot with captureBeyondViewport, posts the PNG into the UI.
None was sent out.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-200
- Source
- Dynamic sandbox
You click the extension's screenshot button on a PubMed page.
The extension attaches the debugger interface to the active tab and captures a PNG image.
The capture request asks Chrome to include page content beyond the current viewport.
- Active tab imagePubMed article header for PMID 30293440
The screenshot can include the page content visible to you at the time of capture.
- Off-screen page areaArticle title, authors, citation metadata, and header layout
The capture request can include page content outside the current viewport when Chrome supports it.
- Image datadata:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA
The captured page area is represented as a base64 PNG before it is shown in the extension UI.
Debugger screenshot capture path
Readable background capture method
js/background.jsasync screenshotActiveTabBoundingBox(e) { let t = this, n = t.msgId, r = { active: !0, lastFocusedWindow: !0 }, i = await chrome.tabs.query(r), a = i[0].id; St.log("tab", a); let s = !1; chrome.tabs.query(r, (function(r) { let i = r[0].id; chrome.debugger.attach({ tabId: i }, "1.3", (function() { chrome.debugger.sendCommand({ tabId: i }, "Page.captureScreenshot", { format: "png", fromSurface: !0, captureBeyondViewport: !0, quality: 100, clip: e }, (function(e) { St.log(chrome.runtime.lastError), St.log("background-screenshotBoundingBox", e), e ? (t.responseMessage(e, n), s = !0, chrome.debugger.detach({ tabId: i }, void 0)) : t.responseMessage({}, n, { success: !1 }) })) })) })), setTimeout(() => { s || t.responseMessage({}, n, { success: !1 }) }, 2e3)}Readable content-script request and display path
js/content-script.jsasync function pt(t, e = 0, i = { preProcess: void 0, postProcess: void 0}, r) { null === i || void 0 === i || i.preProcess(); let s = document.body.style.overflow; document.body.style.overflow = "hidden"; let { x: a, y: o, height: l, width: u } = t.getBoundingClientRect(), c = { x: a + scrollX - e, y: o + scrollY - e, height: l + 2 * e, width: u + 2 * e, scale: 1 }, p = await ht(c); if (!p) return document.body.style.overflow = s, null === i || void 0 === i || i.postProcess(), void Object(n["a"])("Some iframes might hinder the ability to capture a screenshot. Would you like to remove them and take a screenshot?", [{ text: "Continue to capture the screenshot", events: { click: () => { let n = document.querySelectorAll("iframe"); for (let t of n) console.log(chrome.runtime.id), mt(t) || t.remove(); pt(t, e, i, r) } }, style: "yes" }, { text: "Cancel", style: "no" }], "warning", 0); document.body.style.overflow = s, null === i || void 0 === i || i.postProcess(); let { screenshotPort: h } = await dt(); h.postMessage({ msg: "addImage", data: { image: p, base64ImageWithHeader: "data:image/png;base64," + p, config: r } }, "*")}async function ht(t) { window.epScreenshotPort && !window.epScreenshotPort.isDisconnect || (ct = window.epScreenshotPort = h("epScreenshotPort")); try { let { data: e } = await ct.sendWithPromise("screenshotActiveTabBoundingBox", t, 500); return e.data } catch (e) { return !1 }}