Is EasyBusiness safe?

High risk

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.…

Kompassv1.0.2Chrome Web Store
79Risk
Who publishes it

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.

Publisher
Kompass
Declared legal entity
Kompass International

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.

app.clicsight.com
Also called by 2 other listings: Getquanty, ClicSight
app.kompass-easylead.com
Also called by 2 other listings
app.ksales.ai
Also called by 2 other listings
easy.kompass-easylead.com
Also called by 2 other listings: Getquanty, ClicSight
ext.getquanty.com
Also called by 2 other listings: Getquanty, ClicSight
my.clicsight.com
Also called by 2 other listings: Getquanty, ClicSight
fr.kompass.com
Also called by 3 other listings
proxy.getquanty.com
Also called by 3 other listings

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
What actually happens
You did this

You use EasyBusiness while a LinkedIn profile is open.

The extension did this

The extension reads the profile page and posts the resulting profile object to its search API.

LinkedIn fields assembled by getLinkedinProfile()
  • Profile name
    Jane Doe

    Identifies the person whose LinkedIn profile you viewed.

  • Role and company
    Sales Director at Example Co.

    Adds workplace context about the person on the page.

  • LinkedIn profile URL
    https://www.linkedin.com/in/jane-doe/

    Ties the request to the exact public profile being processed.

  • Experience and page content
    Experience: Account Executive, Example Co.; Skills: prospecting, CRM

    Can include profile sections such as about text, skills, recommendations, and experience.

  • Browser and extension metadata
    EasyBusiness 1.0.2; Mozilla/5.0 Chrome/126.0.0.0

    Adds context about the browser and EasyBusiness version used for the request.

Captured request
POSThttps://easy.kompass-easylead.com/api/search
The code that does this

LinkedIn profile object and POST path

Readable version

Deobfuscated LinkedIn scraper

deobfuscated/js/toolbar.js
async 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.js
async 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.js
async 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.js
easybusiness: {        URL_GETQUANTY: "https://easy.kompass-easylead.com",        API_GETQUANTY: "https://easy.kompass-easylead.com/api",
Destination receiving the profile object
    • 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
What actually happens
You did this

You use EasyBusiness while viewing a supported CRM contact record.

The extension did this

The extension reads contact fields from the CRM page and posts them to its search API.

CRM fields assembled by the contact parsers
  • Contact name
    Jane Doe

    Identifies the person whose CRM record is open.

  • Email address
    jane.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 position
    Example Co.; Sales Director

    Adds workplace context from the CRM record.

  • CRM page URL and source
    https://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 metadata
    EasyBusiness 1.0.2; Mozilla/5.0 Chrome/126.0.0.0

    Adds context about the browser and EasyBusiness version used for the request.

Captured request
POSThttps://easy.kompass-easylead.com/api/search
The code that does this

CRM URL routing and contact-field parsers

Readable version

Deobfuscated CRM router

deobfuscated/js/toolbar.js
parsePageProfile = 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.js
function 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.js
getKompassCrmContacts = 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.js
getZohoCrmContact = 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.js
getDivaltoContact = 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.js
getSalesforceContact = 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.js
getDynamicsContact = 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  }
The code that does this

Search request POST path

Readable version

Deobfuscated content-to-background message

deobfuscated/js/toolbar.js
async 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.js
async 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.js
easybusiness: {        URL_GETQUANTY: "https://easy.kompass-easylead.com",        API_GETQUANTY: "https://easy.kompass-easylead.com/api",
Destination receiving CRM contact objects
    • 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
What actually happens
You did this

You click the EasyBusiness extension icon on any website that is not a recognised CRM or LinkedIn page.

The extension did this

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.

Data fields sent to easy.kompass-easylead.com on any non-CRM page
  • Page body text
    BBC 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 URL
    https://www.bbc.co.uk/news/articles/c9dl0pg7d34o

    The full address of the page you were on when you clicked the icon.

  • Meta description
    Breaking 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.

  • Keywords
    news, bbc, breaking, sport

    Any keywords listed in the page's meta[name=keywords] tag.

  • Domain
    bbc.co.uk

    The hostname of the page, derived from the URL.

  • Social media links
    https://www.facebook.com/bbcnews

    Facebook, LinkedIn, Twitter, and Instagram links found via meta tags or JSON-LD structured data on the page.

  • Email address
    contact@example.com

    Any mailto: link found on the page.

  • Phone number
    +44 20 7946 0958

    Any tel: link found on the page.

  • User-agent string
    Mozilla/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 version
    1.0.2

    The installed version of EasyBusiness, sent with every request.

Captured request
POSThttps://easy.kompass-easylead.com/api/search

Server returns a profile enrichment result with defaultUrl pointing to the EasyBusiness panel URL for the matched company.

Headers
Content-type
application/json; charset=UTF-8
Body
{  "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"}
The code that does this

getCompanyProfile(); the fallback scraper that runs on any unrecognised website

Readable version
js/toolbar.js
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  };};
Where the scraped page data is sent
    • 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

Updated 30 September 2026nphpkgiplkjfpamdchnfdknfcaeilohn