Is Email Finder-Kendo Sourcing Ninja safe?

High risk

Kendo Sourcing Ninja is high risk. The extension posts to kendoemailapp.com/kendoquerystatus2 when a LinkedIn profile loads, carrying the profile slug and fields name, company, title, company ID, member ID, user, location, platform, related companies, version, checksum.…

kendo ltdv6.704Chrome Web Store
75Risk

AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.

Publishers can request a review.

Findings

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

LinkedIn profile fields posted on profile visits

The extension posts to kendoemailapp.com/kendoquerystatus2 when a LinkedIn profile loads, carrying the profile slug and fields name, company, title, company ID, member ID, user, location, platform, related companies, version, checksum.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You open a LinkedIn member profile page.

The observed test page was the LinkedIn profile for williamhgates.

The extension did this

The extension posts the viewed profile identifier and profile fields to Kendo.

Dynamic analysis observed three POST requests after the profile page loaded.

02EvidenceFIELD TABLE
Fields prepared for the profile-status request
FieldValueWhy it matters
Viewed profile
urls=williamhgatesIdentifies the LinkedIn member profile you opened.
Profile identity fields
nm="", comp="", title="", loc="" in the recorded requestCan include the person's displayed name, title, company, company ID, member ID, and location when those values are available on the page.
LinkedIn context
platform="", comps=""Adds context about the profile source and related companies so the profile visit can be categorized.
Extension metadata
v=6.702 plus crcTies the request to the installed extension version and a checksum generated by the extension.
03EvidenceNETWORK CAPTURE
Captured request
POSThttps://kendoemailapp.com/kendoquerystatus2
Dynamic analysis observed three POST requests after the LinkedIn profile page loaded.
Headers
Acceptapplication/json, application/xml, text/plain, text/html, *.*
Content-Typeapplication/json
04EvidenceCODE COMPARE
The code that does this

Profile visit path from content script to Kendo

What it actually does
Readable content script sends profile fieldsdeobfuscated/contentScript.bundle.js
chrome.runtime.sendMessage({
  contentScriptQuery: _e.getstatus,
  data: {
    urls: i,
    nm: c,
    comp: m,
    title: u,
    compid: p,
    id: f,
    usr: h,
    loc: g,
    platform: b,
    comps: y
  }
}, function(r) {
  chrome.runtime.sendMessage({ contentScriptQuery: _e.gettop }, function(a) {
    if (r) {
      var v = "";
      r && r.found && r.status && (v = r.status);
      var x = document.createElement("div");
      x.id = "kendo_elem";
    }
  });
});
Readable background worker posts to kendoquerystatus2deobfuscated/background.bundle.js
if (t.contentScriptQuery == o.getstatus) {
  t.data && (t.data.v = chrome.runtime.getManifest().version);
  j = i(JSON.stringify(t.data));
  return t.data.crc = j, fetch("https://kendoemailapp.com/kendoquerystatus2", {
    method: "POST",
    headers: {
      Accept: "application/json, application/xml, text/plain, text/html, *.*",
      "Content-Type": "application/json"
    },
    body: JSON.stringify(t.data)
  }).then(function(t) {
    return t.json();
  }).then(function(t) {
    !c && t && t.widgettop && t.widgettop > 20 && (c = t.widgettop), n(t);
  }).catch(function(t) {
    return console.log("Error:", t);
  }), !0;
}
05EvidenceTHIRD PARTY LIST
External destination for this claim
  • kendoemailapp.com

    Receives LinkedIn profile-status requests at /kendoquerystatus2.

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

Saved LinkedIn profile records posted to Kendo

Pressing save builds a LinkedIn profile record sent to kendoemailapp.com/kendoquery.

Fields can include URL, notes, status, subject, message, member name, pools, rate, mobile, website, email, title, skills, location, salary, memberID.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You save a LinkedIn profile with the extension.

The save button is disabled until the member-name field has content.

The extension did this

The extension sends a saved-profile record to Kendo.

The record combines values entered in the extension UI with fields read from the LinkedIn page.

02EvidenceFIELD TABLE
Fields in the saved-profile object
FieldValueWhy it matters
Profile URL and IDs
url=https://www.linkedin.com/in/jane-recruiter, memberID=123456789 (illustrative)Identifies the exact LinkedIn profile saved and links the record to LinkedIn member and talent IDs.
Entered recruiting notes
notes=Follow up next week, status=Contacted, salary=120000 (illustrative)Carries the notes, status, subject, message body, pool, assignment, rate, and salary values entered while saving the profile.
Contact fields
workemail=person@example.com, mobile=+1-415-555-0142 (illustrative)Can include work email, personal email, phone number, website, and the saved person's displayed name.
Profile page details
title=Engineering Manager, location=San Francisco, imageURL=https://media.licdn.com/profile.jpg (illustrative)Adds LinkedIn page details such as title, company, location, skills, current job, and profile image URL.
03EvidenceNETWORK CAPTURE
Captured request
POSThttps://kendoemailapp.com/kendoquery
The source-confirmed request path posts the saved-profile object; unauthenticated dynamic testing did not capture a live body.
Headers
Acceptapplication/json, application/xml, text/plain, text/html, *.*
Content-Typeapplication/json
04EvidenceCODE COMPARE
The code that does this

Save button path from content script to Kendo

What it actually does
Readable content script builds the saved-profile objectdeobfuscated/contentScript.bundle.js
onClick: function() {
  B(!0);
  var e = ke(Ye) ? Vi : Ye,
    n = Oe.filter(function(e) { return e.active; }).map(function(e) { return "".concat(e.text); }),
    r = n.join("~"),
    a = Me(window.location.href),
    o = {
      notes: we,
      url: ue,
      status: e,
      skiilsyears: oe,
      subject: nt,
      body: ot,
      membername: K,
      pools: r,
      rate: null != Ke ? Ke : 0,
      mobile: P,
      website: I,
      ___pools: n,
      workemail: C,
      email: M,
      title: Te,
      assigned: $,
      skills: ne,
      location: le,
      job: S,
      salary: A,
      talentid: a
    },
    s = document.querySelector("[data-member-id]");
  if (s && (o.memberID = s.attributes["data-member-id"].value), ((s = document.querySelector('[aria-label="Current company"]')) || (s = document.querySelector("[data-test-position-entity-company-link]"))) && (o.memberCompany = s.innerText.trim()), 1 == (s = document.getElementsByClassName("pv-top-card-profile-picture__image")).length) {
    var l = s[0].attributes.getNamedItem("src");
    l && (o.imageURL = l.value);
  }
  chrome.runtime.sendMessage({
    contentScriptQuery: _e.postdata,
    data: o
  }, function(r) {
    v(e), Ie(n), i(!1), B(!1);
    var a = new CustomEvent("profilechanged", {
      detail: { status: Ye, id: Le, pools: n, rate: Ke, assigned: $, nm: K, sk: ne, sky: oe }
    }),
    o = document.getElementById("kendoplugin");
    o && o.dispatchEvent(a), t.onClose && t.onClose(Ye);
  });
}
Readable background worker posts to kendoquerydeobfuscated/background.bundle.js
if (t.contentScriptQuery == o.postdata) return t.data && (t.data.v = chrome.runtime.getManifest().version), fetch("https://kendoemailapp.com/kendoquery", {
  method: "POST",
  headers: {
    Accept: "application/json, application/xml, text/plain, text/html, *.*",
    "Content-Type": "application/json"
  },
  body: JSON.stringify(t.data)
}).then(function(t) {
  return t.json();
}).then(function(t) {
  n(t);
}).catch(function(t) {
  return console.log("Error:", t);
}), !0;
05EvidenceTHIRD PARTY LIST
External destination for this claim
  • kendoemailapp.com

    Receives saved LinkedIn profile records at /kendoquery.

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-200
SourceAI SANDBOX

LinkedIn profile details sent in a Kendo query URL

A LinkedIn profile update-button click sends its URL, candidate ID, company ID, and name to the background script, which GETs kendoemailapp.com/kendoquery2 with those as parameters.

Unauthenticated DA couldn't capture this; needs a login.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You press the extension update button on a LinkedIn profile.

The extension did this

The extension sends profile identifiers and the displayed name to Kendo in URL query parameters.

02EvidenceFIELD TABLE
Fields placed in the Kendo query URL
FieldValueWhy it matters
LinkedIn profile URL
https://www.linkedin.com/in/williamhgatesThis identifies the LinkedIn profile page you were viewing when you clicked the extension button.
Displayed profile name
William H. GatesThis can identify the LinkedIn member associated with the lookup.
Candidate ID
18492517This links the request to the extension or Kendo record for that profile.
Company ID
1035This adds company context to the profile lookup.
03EvidenceNETWORK CAPTURE
Captured request
GEThttps://kendoemailapp.com/kendoquery2?url=https%3A%2F%2Fwww.linkedin.com%2Fin%2Fwilliamhgates&id=18492517&cmp=1035&mid=&nm=William%20H.%20Gates
04EvidenceCODE COMPARE
The code that does this

Click handler and Kendo query construction

What it actually does
Readable click-handler excerptcontentScript.bundle.js
handleShow: function() {
  var e;
  (t.memberurl || t.candidateID) && (chrome.runtime.sendMessage({
    contentScriptQuery: _e.allcandidates
  }, function(e) {
    ut(e)
  }), t.candidateID && Ce(t.candidateID), U(!0), chrome.runtime.sendMessage({
    contentScriptQuery: _e.getdata,
    url: t.memberurl,
    id: t.candidateID,
    cmp: null !== (e = t.memberCompanyID) && void 0 !== e ? e : -1,
    nm: t.memberName
  }, function(e) {
    if (U(!1), null != e && "" != e) {
      var x = JSON.parse(e);
      if (x.needlogin) return b(!0);
    }
  }))
}
Readable background request branchbackground.bundle.js
if (t.contentScriptQuery == o.getdata) return fetch("https://kendoemailapp.com/kendoquery2?url=".concat(encodeURIComponent(null !== (a = t.url) && void 0 !== a ? a : ""), "&id=").concat(encodeURIComponent(null !== (s = t.id) && void 0 !== s ? s : ""), "&cmp=").concat(encodeURIComponent(null !== (l = t.cmp) && void 0 !== l ? l : ""), "&mid=").concat(encodeURIComponent(null !== (m = t.memberid) && void 0 !== m ? m : ""), "&nm=").concat(encodeURIComponent(null !== (u = t.nm) && void 0 !== u ? u : ""))).then(function(t) {
  return t.text()
}).then(function(t) {
  return n(t)
}).catch(), !0;
05EvidenceTHIRD PARTY LIST
Destination for the profile query
  • kendoemailapp.com

    Receives the profile lookup GET request at /kendoquery2 with LinkedIn profile fields in the query string.

Updated 20 September 2026kecadfolelkekbfmmfoifpfalfedeljo