Is LI Prospect Finder safe?

Medium risk

LIPF is medium risk. When LI Prospect Finder can't parse certain LinkedIn search-result pages locally, it posts the page HTML to li-prospect-finder.com. The posted JSON's html field carries the full document, including rendering data used to extract records.

info@lipf.storev3.2.14Chrome Web Store
45Risk

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

Publishers can request a review.

Findings

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

LinkedIn search HTML sent to parsing endpoints

When LI Prospect Finder can't parse certain LinkedIn search-result pages locally, it posts the page HTML to li-prospect-finder.com.

The posted JSON's html field carries the full document, including rendering data used to extract records.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You run a LinkedIn company or people search through the extension.

The fallback paths appear when LinkedIn pages use the newer rendering data or when local people parsers return no results.

The extension did this

The extension posts the LinkedIn search-result HTML to its vendor server for parsing.

The request body is JSON with an html field containing the page document.

02EvidenceFIELD TABLE
Data placed in the parsing request
FieldValueWhy it matters
LinkedIn page HTML
Illustrative HTML: <html><script>window.__como_rehydration__ = {"data":{"searchDashClustersByAll":{"metadata":{"primaryResultType":"COMPANIES"}}}}</script></html>This can include the search-result markup and embedded LinkedIn rendering data for the profiles or companies shown on the page.
Request field name
htmlThe server receives the page document under a single html field, which is enough to reconstruct the search results being parsed.
03EvidenceNETWORK CAPTURE
Captured request
POSThttps://li-prospect-finder.com/extension/api/companies/parse
Headers
Acceptapplication/json
Ext-Version3.2.12
Content-Typeapplication/json
04EvidenceNETWORK CAPTURE
Captured request
POSThttps://li-prospect-finder.com/extension/api/peoples/parse
Headers
Acceptapplication/json
Ext-Version3.2.12
Content-Typeapplication/json
05EvidenceCODE COMPARE
The code that does this

Fallbacks that send LinkedIn search-result HTML

What it actually does
Company search fallback in readable formdeobfuscated/js/li/search/searchCompanies.js
async function getCompaniesFromDefaultSearch() {
  let e = WEB_REQUEST_LI_API_URLS.COMPANIES_SEARCH;
  !0 === tab.url?.toLowerCase().includes("schools") && (e = WEB_REQUEST_LI_API_URLS.SCHOOLS_SEARCH);
  var a = await getLocalStorageValue(e);
  a && a[tab.id] && (searchUrl = a[tab.id], csrfToken) && (a = {
    "csrf-token": this.csrfToken,
    "x-restli-protocol-version": "2.0.0"
  }, 0 < searchUrl.indexOf(WEB_REQUEST_LI_API_URLS.NEW_API) && (a.accept = "application/vnd.linkedin.normalized+json+2.1"), $.ajaxSetup({
    headers: a,
    global: !1,
    type: "GET"
  }));
  let t = !1,
    s = "";
  tab.url?.toLowerCase().includes("companies") && (s = await $.get(tab.url) || "", t = s.includes("window.__como_rehydration__")), t ? companies = await apiCompaniesInfoFromHtml({
    html: s
  }) || [] : (a = await $.get(searchUrl), (companies = liSearchCompaniesParser.handle(a)) && 0 !== companies.length || (companies = liSearchCompaniesParser.getCompanies(a))), renderCompaniesList()
}
People parser fallback in readable formdeobfuscated/js/li/search/searchProspectsParser.js
async getPeopleListV4(e) {
  return {
    people: (await apiProspectsInfoFromHtml({
      html: e
    }) || []).map(e => ({
      ...e,
      source: "linkedIn",
      searchLink: `https://www.linkedin.com/voyager/api/identity/dash/profiles?q=memberIdentity&memberIdentity=${e.source_id_2}&decorationId=com.linkedin.voyager.dash.deco.identity.profile.FullProfileWithEntities-26`
    })),
    hasUnadded: !1
  }
}
Automated company search pagination in readable formdeobfuscated/js/li/autoSearch/autoSearchCompanyTask.js
async goToNextSearchPage() {
  let t = !1;
  if (!this.isFinished && !this.isPaused && this.isStarted) {
    var s;
    if (this.currentCompanies = [], (!0 === this.urlStart?.toLowerCase().includes("results/companies") || !0 === this.urlStart?.toLowerCase().includes("results/schools") || 0 < this.urlCurrent.indexOf(WEB_REQUEST_LI_API_URLS.NEW_API)) && (t = !0), +this.pageCurrent != +this.pageStart) return !(+this.pageCurrent <= +this.pageFinish) || (this.errorInternetCount = 0, this.urlCurrent = this.getCurrentSearchUrl(this.urlStart), 0 < this.urlCurrent.indexOf(WEB_REQUEST_LI_API_URLS.NEW_API) && $.ajaxSetup({
      headers: {
        accept: "application/vnd.linkedin.normalized+json+2.1"
      },
      global: !1,
      type: "GET"
    }), "string" == typeof(s = await $.get(this.urlCurrent)) && s.includes("window.__como_rehydration__") ? this.companies = await apiCompaniesInfoFromHtml({
      html: s
    }) : this.companies = liSearchCompaniesParser.handle(s), this.companies && 0 !== this.companies.length || (this.list.length ? this.companies = this.list : this.companies = t ? liSearchCompaniesParser.getCompanies(s) : getCompaniesSN(s), this.checkIsPageAbsentError(s, t)), this.isPageAbsentError) ? void await this.finishPageHandler() : (await taskManager.setUnfinishedTask(getDeepCopyOfObject({
      ...this,
      currentCompanies: []
    })), void this.sendCompanyBlock());
    this.list.length ? this.companies = this.list : this.companies = localStorage.companies ? JSON.parse(localStorage.companies) : [], this.needsSendCompaniesCount = this.companies.length + (this.pageFinish - this.pageStart) * this.companyCountOnPage, await this.sendCompanyBlock()
  }
}
Automated people search pagination in readable formdeobfuscated/js/li/autoSearch/autoSearchTask.js
async goToNextSearchPage() {
  if (!this.isFinished && !this.isPaused && this.isStarted)
    if (+this.pageCurrent > +this.pageFinish) this.finish && this.finish();
    else {
      this.errorInternetCount = 0, this.urlCurrent = this.getCurrentSearchUrl(this.urlStart);
      var t = this;
      if (this.list) i();
      else {
        let e = this.urlCurrent;
        var s = {
            "csrf-token": this.csrfToken,
            "x-restli-protocol-version": "2.0.0"
          },
          s = (0 < e.indexOf(WEB_REQUEST_LI_API_URLS.NEW_API) && (s.accept = "application/vnd.linkedin.normalized+json+2.1"), this.requestMethod === REQUEST_METHODS.POST && (e = this.urlCurrent.split("?")[0], s["Content-Type"] = "application/x-www-form-urlencoded", s["x-http-method-override"] = "GET"), {
            method: this.requestMethod,
            headers: s
          });
        this.requestMethod === REQUEST_METHODS.POST && (s.body = this.urlCurrent.split("?")[1]);
        try {
          i(await (await fetch(e, s)).text())
        } catch (e) {
          0 === e.status ? (t.error = !0, t.errorCode = 0, t.errorOnPageGlobal()) : t.errorOnPage()
        }
      }
    } async function i(e) {
    !e && t.list ? (t.people = t.list, t.list = void 0) : (t.people = t.getPeopleList(e), t.people && t.people?.length || t.isSalesNavInt || (t.people = (await (new searchProspectsParser).getPeopleListV4(e))?.people)), t.getTrackingInfo && (t.trackingInfo = t.getTrackingInfo(e)), t.people && 0 < t.people.length ? (e = await t.checkPrevAddedPeople(t.people) || !1, t.needRecheckPrevAdded = e, await t.checkRecentlyUpdatedPeoples(t.people), t.itemsParsed = 0, t.waitAndGetPerson(), await reRenderTask(t)) : (t.itemsParsed = 0, t.waitAndGetPerson(), reRenderTask(t)), await reRenderTask(t)
  }
}
06EvidenceCODE COMPARE
The code that does this

The API wrapper builds POST requests to the parsing endpoints

What it actually does
Endpoint constants and POST helper in readable formdeobfuscated/js/apiMethods.js
let API_HOST = APP_HOST + "/extension/api",
  USER_BALANCE = "/user/balance",
  PEOPLE_CREATE = "/peoples/create",
  PEOPLE_CONTACTS = "/peoples/contacts",
  PEOPLE_RECENTLY_UPDATED = "/peoples/recently-updated",
  COMPANIES_CREATE = "/companies/create",
  LISTS_BY_USER = "/lists/get-by-user-id",
  LISTS_BY_PROSPECTS = "/lists/get-by-peoples-ids",
  LISTS_BY_COMPANIES = "/lists/get-by-companies-ids",
  NEWS_GET = "/news/get-last",
  LI_HTML = "/linkedin/collect",
  COMPANIES_PARSE = "/companies/parse",
  PROSPECTS_PARSE = "/peoples/parse";

function post(e, a) {
  return fetch(e, {
    method: "POST",
    body: JSON.stringify(a),
    headers: {
      "Content-Language": getUILanguage(),
      "Ext-Version": chrome.runtime.getManifest().version,
      "Content-Type": "application/json",
      Accept: "application/json"
    }
  })
}
Parsing endpoint wrappers in readable formdeobfuscated/js/apiMethods.js
async function apiCompaniesInfoFromHtml(e) {
  e = await post(API_HOST + COMPANIES_PARSE, e);
  return e.ok && (await e.json())?.companies || []
}
async function apiProspectsInfoFromHtml(e) {
  e = await post(API_HOST + PROSPECTS_PARSE, e);
  return e.ok && (await e.json())?.peoples || []
}
07EvidenceTHIRD PARTY LIST
Server that receives the parsing requests
  • li-prospect-finder.com

    LI Prospect Finder vendor host that receives LinkedIn search-result HTML at /extension/api/companies/parse and /extension/api/peoples/parse.

Updated 30 September 2026mdhjhplkmldfjgoegbdmallcdhlecfcn