Is EasyBusiness safe?
EasyBusiness is high risk. On a LinkedIn profile page, EasyBusiness reads profile URL, name, role, company, and content, sent via background script to easy.kompass-easylead.com/api/search with version and user agent. LinkedIn values weren't captured; login required.…
Who publishes itKompass International - 1 other listing from the same operator, 1 of them carrying a finding
Kompass International - 1 other listing from the same operator, 1 of them 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, 211 users between them. 1 of them carries a finding.
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
LinkedIn profile details are posted to EasyBusiness API
On a LinkedIn profile page, EasyBusiness reads profile URL, name, role, company, and content, sent via background script to easy.kompass-easylead.com/api/search with version and user agent.
LinkedIn values weren't captured; login required.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-200
- Source
- Dynamic sandbox
You use EasyBusiness while a LinkedIn profile is open.
The extension reads the profile page and posts the resulting profile object to its search API.
- Profile nameJane Doe
Identifies the person whose LinkedIn profile you viewed.
- Role and companySales Director at Example Co.
Adds workplace context about the person on the page.
- LinkedIn profile URLhttps://www.linkedin.com/in/jane-doe/
Ties the request to the exact public profile being processed.
- Experience and page contentExperience: Account Executive, Example Co.; Skills: prospecting, CRM
Can include profile sections such as about text, skills, recommendations, and experience.
- Browser and extension metadataEasyBusiness 1.0.2; Mozilla/5.0 Chrome/126.0.0.0
Adds context about the browser and EasyBusiness version used for the request.
LinkedIn profile object and POST path
Deobfuscated LinkedIn scraper
deobfuscated/js/toolbar.jsasync function getLinkedinProfile(a = 0) { function b(p, r, z = "") { return (p = p.querySelector(r)) ? p.innerText : z } function c(p) { try { const r = (new URL(p)).pathname.match(/^\/in\/[^/]+\/?/i); return r ? `https://www.linkedin.com${r[0].replace(/\/$/,"")}/` : "" } catch (r) { return "" } } const d = document.location.href; var f = b(document, '[data-view-name="profile-top-card-verified-badge"]'), g = f.split(" ")[0]; let h = f.replace(g + " ", ""), k = getAttr(document, '[data-view-name="profile-top-card-member-photo"] img', "src"); const l = getAttr(document, "img.EntityPhoto-square-1", "src"); let m = ""; var n = ""; try { var q = document.querySelector("#experience"); m = q && q.parentNode && q.parentNode.innerText ? q.parentNode.innerText : ""; m = m.split(/\r?\n/).length > 1 ? [...(new Set(m.split(/\r?\n/)))].join("\n") : m; n = (n = /^(\d\s\w{0,5}\s{0,1}){1,2}$/.test(m.split(/\r?\n/)[2]) ? m.split(/\r?\n/)[1] : m.split(/\r?\n/)[2]) ? n.replace(" · Permanent", "") : n } catch (p) {} q = b(document, "div.pv-entity__summary-info--background-section"); let x = b(document, "div.inline-show-more-text"), w = getAttr(document, '[data-control-name="background_details_company"]', "href"); w = w ? "https://linkedin.com" + w : ""; let v = getAttr(document, '[data-view-name="edge-creation-connect-action"] a', "href"); v = v ? (v = v.split("vanityName=")[1]) && v.length ? `https://linkedin.com/in/${v}` : "" : c(d); var t = document.querySelector('[data-view-name="profile-top-card-verified-badge"]')?.parentElement?.nextElementSibling?.innerText?.trim() || ""; t = t.split("\n")[0]; var u = t.indexOf(" chez ") > 0 ? t.split(" chez ") : t.split(" at "); t = u[0]; t || (t = (t = document.querySelectorAll('[componentkey*="com.linkedin.sdui.profile.card"] p')[2]) ? t.innerText : ""); n = (n = document.querySelectorAll('[componentkey*="com.linkedin.sdui.profile.card"] [role="button"]')[3]) ? n.innerText : ""; u = (u = (u = document.querySelectorAll('[componentkey*="entity-collection-item"] figure')[0]) ? u.getAttribute("aria-label") : null) ? u.split(" logo")[0] : null; n == f && (n = u); f || (console.log("[FAILED ON NEW MODE] H1 FALLBACK.. "), document.querySelector("h1") && (f = document.querySelector("h1").innerText, g = f.split(" ")[0], h = f.replace(g + " ", ""), n = u, t = document.querySelector("div.text-body-medium.break-words") ? document.querySelector("div.text-body-medium.break-words").innerText : "", u = [], u = t.indexOf(" chez ") ? t.split(" chez ") : t.split(" at "), t = u[0])); var y = ""; u = ""; if (document.querySelector("body")) { y = {}; let p = document.querySelector("body").cloneNode(!0).querySelectorAll(".pv-profile-card__anchor"); for (let r = 0; r < p.length; r++) { const z = p[r].id || "section_" + r; if (z) { const A = p[r].parentElement.cloneNode(!0); A.querySelectorAll('[class*="hidden"]').forEach(B => B.innerHTML = ""); y[z] = A.textContent.replaceAll("\n", " ").replaceAll("\t", " ").replaceAll(" ", " ").replaceAll("..", ".") } "about,recommendations,skills,experience,section_".indexOf(z) >= 0 && (u += "\n\n####" + z + ":\n\n" + y[z]) } y = "##### profile : " + f + "\n\n\n##### position : " + (t + "\n\n\n##### lastposition : ") + (q + "\n\n\n"); y += "##### company : " + n + "\n\n\n"; y += u; y = y.replace(/\s\s+/g, " ").replaceAll("..", ".") } f = { insert: document.querySelector("div.text-body-medium.break-words"), avatar: k, logo: l, cv: m, clinkedin: w, linkedin: v, url: d, cdesc: x, phone: "", email: "", source: "linkedin", content: y, company: n, position: t.trim(), fullname: f.trim(), firstname: g.trim(), lastname: h.trim(), lastposition: q.trim(), id: 0 }; g = p => new Promise(r => setTimeout(r, p)); return !n && a < 4 ? (console.log("[4sec wait] retry", a), await g(1E3), getLinkedinProfile(a + 1)) : { url: d, contacts: [f] }}Deobfuscated content-to-background message
deobfuscated/js/toolbar.jsasync function makeSearchRequest(a) { try { console.log("[TOOLBAR] Starting search request for:", a); setLauncherLoading(!0); const b = new Promise((f, g) => { setTimeout(() => g(Error("Content script search timeout")), 15E3) }), c = promisify(chrome.runtime.sendMessage)({ action: "search-parsed-data", pageProfile: a }), d = await Promise.race([c, b]); console.log("[TOOLBAR] Search response:", d); if (d && d.status == "ko") currentUrlGlobal = `${URL_GETQUANTY}/login?timestamp=${timestamp}`; else if (d && d.data) { let f = d.data; d.data?.defaultUrl == "/search-suggest-companies" && (f = preparePrefeedUrl(a)); currentUrlGlobal = f.defaultUrl } else console.warn("[TOOLBAR] Invalid search response:", d), currentUrlGlobal = `${URL_GETQUANTY}/login?timestamp=${timestamp}`; navigateIframe(currentUrlGlobal); setLauncherLoading(!1); return d } catch (b) { return console.error("[TOOLBAR] Search request failed:", b), setLauncherLoading(!1), currentUrlGlobal = `${URL_GETQUANTY}/login?timestamp=${timestamp}`, navigateIframe(currentUrlGlobal), { status: "ko", msg: "client-error" } }}Deobfuscated background POST
deobfuscated/background.jsasync function searchParsedData(a, c) { try { const b = chrome.runtime.getManifest().version, d = navigator.userAgent, e = new Promise((f, h) => { setTimeout(() => h(Error("Search request timeout")), 6E4) }), g = fetch(`${API_GETQUANTY}/search`, { method: "POST", headers: { "Content-type": "application/json; charset=UTF-8" }, body: JSON.stringify({ ...a, extensionVersion: b, userAgent: d }) }); Promise.race([g, e]).then(onStatus).then(f => { console.log("[SEARCH] Success:", f); c({ status: "ok", data: f }) }).catch(f => { console.log("[SEARCH] Request failed:", f); c({ status: "ko", msg: "no-token" }) }) } catch (b) { console.error("[SEARCH] Critical error:", b), c({ status: "ko", msg: "critical-error" }) }}Deobfuscated EasyBusiness API base
deobfuscated/config.jseasybusiness: { URL_GETQUANTY: "https://easy.kompass-easylead.com", API_GETQUANTY: "https://easy.kompass-easylead.com/api",- easy.kompass-easylead.com
Receives the EasyBusiness /api/search POST containing the page profile object and request metadata.
CRM contact fields are posted to EasyBusiness API
EasyBusiness has CRM parsers for HubSpot, Salesforce, Zoho, Dynamics, Divalto, and Kompass.
They build contact records and POST them to easy.kompass-easylead.com/api/search.
CRM values weren't captured live; those CRMs required login.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Dynamic sandbox
You use EasyBusiness while viewing a supported CRM contact record.
The extension reads contact fields from the CRM page and posts them to its search API.
- Contact nameJane Doe
Identifies the person whose CRM record is open.
- Email addressjane.doe@example.com
Can directly identify and contact the person in the CRM record.
- Phone number+1 415 555 0134
Can directly identify or contact the person in the CRM record.
- Company and positionExample Co.; Sales Director
Adds workplace context from the CRM record.
- CRM page URL and sourcehttps://app.hubspot.com/contacts/123/record/0-1/456; source: hubspot
Shows which CRM platform and record page supplied the contact data.
- Browser and extension metadataEasyBusiness 1.0.2; Mozilla/5.0 Chrome/126.0.0.0
Adds context about the browser and EasyBusiness version used for the request.
CRM URL routing and contact-field parsers
Deobfuscated CRM router
deobfuscated/js/toolbar.jsparsePageProfile = async function() { locationUrl = document.location.href; if (locationUrl.indexOf("linkedin.com/in/") > 0) return getLinkedinProfile(); if (locationUrl.indexOf("linkedin.com/sales/lead") > 0) return getSalesNavProfile(); if (locationUrl.indexOf("linkedin.com/company") > 0) return getLinkedinCompanyProfile(); if (locationUrl.indexOf("linkedin.com/search/results/people") > 0) return getLinkedinContacts(); if (locationUrl.indexOf("linkedin.com/sales/search/people") > 0) return getSalesNavContactsSales(); if (locationUrl.indexOf("app.nomination.fr/contact") > 0) return getNominationProfile(); if ((locationUrl.indexOf("app.hubspot.com/") > 0 || locationUrl.indexOf("app-eu1.hubspot.com/") > 0) && locationUrl.indexOf("/record/0-1/") > 0) return getHubspotProfile(); if ((locationUrl.indexOf("app.hubspot.com/") > 0 || locationUrl.indexOf("app-eu1.hubspot.com/") > 0) && locationUrl.indexOf("/record/0-2/") > 0) return getHubspotCompanyProfile(); if (locationUrl.indexOf("nocrm.io/leads/") > 0 || locationUrl.indexOf("nocrm.io/spreadsheets/") > 0 && locationUrl.indexOf("/rows/") > 0) return getNocrmContacts(); if (locationUrl.indexOf("easybusiness#/") > 0 && locationUrl.indexOf("/crm/contact/") > 0) return getKompassCrmContacts(); if (locationUrl.indexOf("easybusiness#/") > 0 && locationUrl.indexOf("/contact/") > 0) return getKompassDetailContact(); if (locationUrl.indexOf("easybusiness#/") > 0 && locationUrl.indexOf("/crm/lead/") > 0) return getKompassCrmLead(); if (locationUrl.indexOf("easybusiness#/") > 0 && locationUrl.indexOf("/crm/company/") > 0) return getKompassCrmCompany(); if (locationUrl.indexOf("easybusiness#/") > 0 && locationUrl.indexOf("/detail/") > 0) return getKompassEasyBusinessCompany(); if (locationUrl.indexOf("kompass.com/c/") > 0) return getKompassSearchCompany(); if (locationUrl.indexOf("crm.zoho.eu/crm/") > 0 && (locationUrl.indexOf("/tab/Leads/") > 0 || locationUrl.indexOf("/tab/Contacts/") > 0)) return getZohoCrmContact(); if (locationUrl.indexOf("crm.zoho.eu/crm/") > 0 && locationUrl.indexOf("/tab/Accounts/") > 0 && locationUrl.indexOf("/custom-view/") < 0) return getZohoCrmCompany(); if (locationUrl.indexOf("weavy.divalto.com/page/marketingInbound/") > 0) return getDivaltoContact(); if (locationUrl.indexOf("weavy.divalto.com/page/customer/") > 0 || locationUrl.indexOf("weavy.divalto.com/page/customerV2/") > 0) return getDivaltoCustomer(); if (locationUrl.indexOf("weavy.divalto.com/page/deal/") > 0) return getDivaltoDealOrProject("deal"); if (locationUrl.indexOf("weavy.divalto.com/page/marketingLead/") > 0 && activePopup && activePopup.querySelector("kendo-window-titlebar")) return getDivaltoMarketingLead(); if (locationUrl.indexOf("weavy.divalto.com/page/project/") > 0) return getDivaltoDealOrProject("project"); if (locationUrl.indexOf("weavy.divalto.com/page/customerContactV2/") > 0) return getDivaltoCustomerContactV2(); if (locationUrl.indexOf("dynamics.com/") > 0 && locationUrl.indexOf("&pagetype=entityrecord&etn=account&id=") > 0) return getDynamicsCompany(); if (locationUrl.indexOf("dynamics.com/") > 0 && locationUrl.indexOf("&pagetype=entityrecord&etn=contact&id=") > 0) return getDynamicsContact(); if (locationUrl.indexOf("dynamics.com/") > 0 && locationUrl.indexOf("&pagetype=entityrecord&etn=lead&id=") > 0) return getDynamicsContact(!0); if (locationUrl.indexOf("lightning.force.com/lightning/") > 0 && locationUrl.indexOf("Account/") > 0 && locationUrl.indexOf("/view") > 0 && locationUrl.indexOf("/related/Contacts/") < 0) return getSalesforceCompany(); if (locationUrl.indexOf("lightning.force.com/lightning/") > 0 && locationUrl.indexOf("Contact/") > 0 && locationUrl.indexOf("/view") > 0) return getSalesforceContact(); if (locationUrl.indexOf("lightning.force.com/lightning/") > 0 && locationUrl.indexOf("Contact/list") > 0) saveSalesforceContactsToStorage(); else if (locationUrl.indexOf("lightning.force.com/lightning/") > 0 && locationUrl.indexOf("related/Contacts/view") > 0) saveSalesforceContactsToStorage(!0); else return locationUrl.indexOf("my.inwink.com") > 0 && (locationUrl.indexOf("/contacts?entityid") > 0 || activePopup && activePopup.querySelector('[data-trad="contact.update.title"]')) ? getInWinkContact() : locationUrl.indexOf("my.inwink.com") > 0 && (locationUrl.indexOf("/companies?entityid") > 0 || activePopup && activePopup.querySelector('[data-trad="company.update.title"]')) ? getInWinkCompanies() : locationUrl.indexOf("my.inwink.com") > 0 && locationUrl.indexOf("/registered?entityid") > 0 || activePopup && activePopup.querySelector('[data-trad="modal.title.updateperson"]') ? getInWinkRegisterContact() : locationUrl.indexOf("my.inwink.com") > 0 && locationUrl.indexOf("/exhibitors") > 0 || activePopup && activePopup.querySelector('[data-trad="modal.title.updateexhibitor"]') ? getInWinkExhibitor() : locationUrl.indexOf("my.inwink.com") > 0 && locationUrl.indexOf("/members?entityid") > 0 ? getInWinkMember() : locationUrl.indexOf("app.ksales.ai/contact/") > 0 ? getKsalesContact() : locationUrl.indexOf("app.ksales.ai/company/") > 0 ? getKsalesCompany() : locationUrl.indexOf("app.ksales.ai/list/contact/") > 0 ? getKsalesContact() : locationUrl.indexOf("app.ksales.ai/list/company/") > 0 ? getKsalesCompany() : getCompanyProfile() };Deobfuscated HubSpot contact parser
deobfuscated/js/toolbar.jsfunction getHubspotProfile(a = 0) { var b = document.location.href; const c = document.querySelector('[data-selenium-test="contact-highlight-details"]'), d = innerText(document, "h2"), f = getAttr(document, "#firstname", "value"), g = getAttr(document, "#lastname", "value"); let h = getAttr(document, "#title", "value") || innerText(document, '[data-selenium-test="highlightSubtitle"]'); var k = h.split(" chez "); h = k[0]; let l = getAttr(document, '[data-field="company"]', "value"); !l && k[1] && (l = k[1]); k = getAttr(document, 'a[href^="tel:"]', "href").replace("tel:", ""); const m = getAttr(document, "#email", "value") || getAttr(document, 'a[href^="mailto:"]', "href").replace("mailto:", ""); b = { contacts: [{ id: 0, source: "hubspot", url: b, insert: c, company: l, position: h, fullname: d, firstname: f, lastname: g, email: m, phone: k, insertAfter: !0 }] }; a += 1; return l && d || !(a < MAX_ITERATION) ? b : new Promise((n, q) => { setTimeout(async () => { n(await getHubspotProfile(a)) }, a * TIME_OUT) })}Deobfuscated Kompass CRM contact parser
deobfuscated/js/toolbar.jsgetKompassCrmContacts = async function(a = 0) { var b = function(q) { return q ? q.innerText : "" }; const c = document.querySelectorAll("div.colControl"); let d = b(c.item(1)).split("\n")[0] || ""; d = d.trim(); var f = b(c.item(1)).split("\n")[1] || ""; f = f.trim(); var g = b(c.item(2)); let h = "", k = ""; g.split("\n").length > 1 ? (h = b(c.item(2)).split("\n")[0] || "", k = b(c.item(2)).split("\n")[1] || "") : g.indexOf("Téléphone") >= 0 ? h = b(c.item(2)).split("\n")[0] || "" : g.indexOf("Email") >= 0 && (k = b(c.item(2)).split("\n")[0] || ""); h = h.replace("Téléphone :", "").trim(); k = k.replace("Email :", "").trim(); b = (b = b(c.item(3))) ? b.trim() : ""; g = d.split(" ")[0]; const l = d.replace(g + " ", ""), m = document.location.href, n = document.querySelector("div.colCrmNiv"); f = { contacts: [{ id: 0, source: "kompass", url: m, insert: n, company: b, position: f, fullname: d, firstname: g, lastname: l, email: k, phone: h, insertAfter: !0 }] }; a += 1; return c && b && d || !(a < MAX_ITERATION) ? f : new Promise((q, x) => { setTimeout(async () => { q(await getKompassCrmContacts(a)) }, a * TIME_OUT) }) }Deobfuscated Zoho CRM contact parser
deobfuscated/js/toolbar.jsgetZohoCrmContact = async function(a = 0) { let b = innerText(document, "#subvalue_LASTNAME"); b.indexOf(".") > 0 && (b = b.split(".")[1] || ""); b = b.trim(); var c = b.split(" ")[0] || ""; const d = b.split(" ")[1] || "", f = innerText(document, "#headervalue_EMAIL"), g = innerText(document, "#headervalue_PHONE"), h = innerText(document, "#busDV_ACCOUNTID"), k = document.location.href, l = document.querySelector("div.dv_header_container"), m = document.querySelector("#topSectionTitle"); c = { contacts: [{ id: 0, source: "zohocrm", url: k, insert: l, company: h, fullname: b, firstname: c, lastname: d, email: f, phone: g, insertAfter: !0 }] }; a += 1; return m && h && b || !(a < MAX_ITERATION) ? c : new Promise((n, q) => { setTimeout(async () => { n(await getZohoCrmContact(a)) }, a * TIME_OUT) }) }Deobfuscated Divalto contact parser
deobfuscated/js/toolbar.jsgetDivaltoContact = async function(a = 0) { var b = function(k) { return (k ? k.innerText : "").trim() }; const c = document.querySelectorAll("div.myRow.d-flex.justify-content-between"), d = c.item(3); if (d) { var f = d.children[1]; var g = b(d.children[0].children[0]); var h = b(f.children[0]).split(" "); h = h.slice(Math.max(h.length - 2, 0)); const k = b(f.children[1]); b = b(f.children[2]); f = (h[1] || "").trim(); h = (h[0] || "").trim(); const l = (f + " " + h).trim(); g = { contacts: [{ id: 0, source: "divalto", url: document.location.href, insert: d, company: g, fullname: l, firstname: f, lastname: h, email: k, phone: b, insertAfter: !0 }] } } a += 1; return c && d || !(a < MAX_ITERATION) ? g : new Promise((k, l) => { setTimeout(async () => { k(await getDivaltoContact(a)) }, a * TIME_OUT) }) }Deobfuscated Salesforce contact parser
deobfuscated/js/toolbar.jsgetSalesforceContact = async function(a = 0) { var b = document.location.href; const c = innerText(document, "head > title").split("|")[0]; var d = c.split(" "); const f = d[0]; d = d.length > 1 ? d.slice(1).join(" ") : ""; const { email: g, company: h } = getSalesforceContactsFromStorage(c.replaceAll(" ", "-").toLowerCase()), k = document.querySelector("div.actionsContainer"); b = { contacts: [{ id: 0, source: "salesforce", url: b, insert: k, company: h, fullname: c, firstname: f, lastname: d, email: g }] }; a += 1; return (!c || c.indexOf("Lightning") >= 0) && a < MAX_ITERATION ? new Promise((l, m) => { setTimeout(async () => { l(await getSalesforceContact(a)) }, a * TIME_OUT) }) : b }Deobfuscated Dynamics contact parser
deobfuscated/js/toolbar.jsgetDynamicsContact = async function(a = !1, b = 0) { let c = ""; var d = extractInputText('input[data-id="fullname_compositionLinkControl_firstname.fieldControl-text-box-text"]'); const f = extractInputText('input[data-id="fullname_compositionLinkControl_lastname.fieldControl-text-box-text"]'), g = extractInputText('input[data-id="mobilephone.fieldControl-phone-text-input"]'), h = extractInputText('input[data-id="emailaddress1.fieldControl-mail-text-input"]'), k = d + " " + f; c = a ? extractInputText('input[data-id="companyname.fieldControl-text-box-text"]') : innerText(document, 'div[data-id="parentcustomerid.fieldControl-LookupResultsDropdown_parentcustomerid_selected_tag_text"]'); const l = document.location.href, m = document.querySelector('div[data-lp-id="form-header-title"]'); d = { contacts: [{ id: 0, source: "dynamics", url: l, insert: m, company: c, fullname: k, firstname: d, lastname: f, email: h, phone: g, insertAfter: !0 }] }; b += 1; return !c && b < MAX_ITERATION ? new Promise((n, q) => { setTimeout(async () => { n(await getDynamicsContact(a = !1, b)) }, b * TIME_OUT) }) : d }Search request POST path
Deobfuscated content-to-background message
deobfuscated/js/toolbar.jsasync function makeSearchRequest(a) { try { console.log("[TOOLBAR] Starting search request for:", a); setLauncherLoading(!0); const b = new Promise((f, g) => { setTimeout(() => g(Error("Content script search timeout")), 15E3) }), c = promisify(chrome.runtime.sendMessage)({ action: "search-parsed-data", pageProfile: a }), d = await Promise.race([c, b]); console.log("[TOOLBAR] Search response:", d); if (d && d.status == "ko") currentUrlGlobal = `${URL_GETQUANTY}/login?timestamp=${timestamp}`; else if (d && d.data) { let f = d.data; d.data?.defaultUrl == "/search-suggest-companies" && (f = preparePrefeedUrl(a)); currentUrlGlobal = f.defaultUrl } else console.warn("[TOOLBAR] Invalid search response:", d), currentUrlGlobal = `${URL_GETQUANTY}/login?timestamp=${timestamp}`; navigateIframe(currentUrlGlobal); setLauncherLoading(!1); return d } catch (b) { return console.error("[TOOLBAR] Search request failed:", b), setLauncherLoading(!1), currentUrlGlobal = `${URL_GETQUANTY}/login?timestamp=${timestamp}`, navigateIframe(currentUrlGlobal), { status: "ko", msg: "client-error" } }}Deobfuscated background POST
deobfuscated/background.jsasync function searchParsedData(a, c) { try { const b = chrome.runtime.getManifest().version, d = navigator.userAgent, e = new Promise((f, h) => { setTimeout(() => h(Error("Search request timeout")), 6E4) }), g = fetch(`${API_GETQUANTY}/search`, { method: "POST", headers: { "Content-type": "application/json; charset=UTF-8" }, body: JSON.stringify({ ...a, extensionVersion: b, userAgent: d }) }); Promise.race([g, e]).then(onStatus).then(f => { console.log("[SEARCH] Success:", f); c({ status: "ok", data: f }) }).catch(f => { console.log("[SEARCH] Request failed:", f); c({ status: "ko", msg: "no-token" }) }) } catch (b) { console.error("[SEARCH] Critical error:", b), c({ status: "ko", msg: "critical-error" }) }}Deobfuscated EasyBusiness API base
deobfuscated/config.jseasybusiness: { URL_GETQUANTY: "https://easy.kompass-easylead.com", API_GETQUANTY: "https://easy.kompass-easylead.com/api",- easy.kompass-easylead.com
Receives the EasyBusiness /api/search POST containing CRM contact objects and request metadata.
Page Content Scraped and Sent to Kompass Server on Any Website
Clicking EasyBusiness's toolbar icon on a non-CRM site reads page text, headings, meta description, phone numbers, emails, and social links, and POSTs it to easy.kompass-easylead.com with URL and user agent.
Confirmed on bbc.co.uk.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-200
- Source
- Dynamic sandbox
You click the EasyBusiness extension icon on any website that is not a recognised CRM or LinkedIn page.
Reads the page's visible text, paragraphs, headings, meta description, keywords, phone numbers, emails, and social links, and sends it to easy.kompass-easylead.com.
The fallback path activates whenever the current URL does not match any of the ~20 whitelisted CRM platforms. The scrape covers any page the user happens to have open.
- Page body textBBC News - Home. Breaking news, sport, TV, radio and a whole lot more. The BBC informs, educates and entertains.
Readable text from every paragraph and heading, joined into one string; captures article content, product descriptions, internal tool text.
- Page URLhttps://www.bbc.co.uk/news/articles/c9dl0pg7d34o
The full address of the page you were on when you clicked the icon.
- Meta descriptionBreaking news, sport, TV, radio and a whole lot more.
The page's og:description or meta[name=description] tag, which often summarises the page's content.
- Keywordsnews, bbc, breaking, sport
Any keywords listed in the page's meta[name=keywords] tag.
- Domainbbc.co.uk
The hostname of the page, derived from the URL.
- Social media linkshttps://www.facebook.com/bbcnews
Facebook, LinkedIn, Twitter, and Instagram links found via meta tags or JSON-LD structured data on the page.
- Email addresscontact@example.com
Any mailto: link found on the page.
- Phone number+44 20 7946 0958
Any tel: link found on the page.
- User-agent stringMozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Your browser and operating system version, appended by the background service worker to every search request.
- Extension version1.0.2
The installed version of EasyBusiness, sent with every request.
Server returns a profile enrichment result with defaultUrl pointing to the EasyBusiness panel URL for the matched company.
- Content-type
- application/json; charset=UTF-8
{ "source": "website", "company": "BBC - Home", "cdesc": "Breaking news, sport, TV, radio and a whole lot more. The BBC informs, educates and entertains.", "content": "BBC News - Home. Breaking news, sport, TV, radio and a whole lot more.", "url": "https://www.bbc.co.uk/", "website": "bbc.co.uk", "domain": "bbc.co.uk", "keywords": "", "cfacebook": "", "clinkedin": "", "ctwitter": "", "cinstagram": "", "cphone": "", "cmail": "", "extensionVersion": "1.0.2", "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"}getCompanyProfile(); the fallback scraper that runs on any unrecognised website
const getCompanyProfile = function() { let bodyText = ""; try { var bodyClone = document.querySelector("body").cloneNode(true); // Strip navigation, modals, paywalls, forms, scripts, footers bodyClone.querySelectorAll( 'style,a,footer,[class*="footer"],script,form,button,[aria-modal="true"],[class*="modal"],[style*="display:none"],[class*="nav-"],[class*="menu-"],[id*="nav-"],[id*="menu-"],[id*="form"],[class*="form"],[class*="paywall"]' ).forEach(el => el.innerHTML = ""); // Extract all paragraph and heading text bodyText = Array.from(bodyClone.querySelectorAll("p,h1,h2,h3")) .map(el => el.innerText.trim()).join("."); bodyText = bodyText.replaceAll("\n", " ").replaceAll("\t", " ") .replaceAll(" ", " ").replaceAll("..", "."); } catch (err) {} const pageUrl = document.location.href; const metaDesc = getAttr(document, 'meta[name="description"]', "content") || getAttr(document, 'meta[property="og:description"]', "content"); // ... reads og:site_name, og:image, twitter:site, article:publisher, // tel: links, mailto: links, JSON-LD structured data (name, logo, // email, address, contactPoint, sameAs for social profiles) ... return { source: "website", company: siteName, keywords: keywords, cdesc: metaDesc, url: pageUrl, domain: domain, content: bodyText, // <-- full page body text cfacebook: facebookUrl, clinkedin: linkedinUrl, ctwitter: twitterHandle, cinstagram: instagramUrl, cphone: phoneNumber, cmail: emailAddress, // address fields from JSON-LD: caddress, czipcode, ccity, ccountry };};- easy.kompass-easylead.com
Kompass EasyLead B2B intelligence platform, owned by Kompass International. Receives page text, meta tags, URL, phone, email, social links from any site used.
+2 more findings not shown