Is LinkMatch for Insightly safe?

Medium risk

LinkMatch for Insightly captures LinkedIn profile, messaging and search API responses and uploads them to app2.linkmatch.com.

On LinkedIn pages, the extension wraps the page's fetch and XHR calls and copies the JSON responses from profile, messaging, Sales Navigator and Recruiter requests. Its content script posts each copy to app2.linkmatch.com along with the user's LinkMatch account email and token. This happens during normal browsing without a save or click.

Yuriy Yazlovytskyyv4.66Chrome Web Store
49Risk
Who publishes it

Logical Pure Minds SRL - 9 other listings from the same operator, 6 of them carrying a finding

What this publisher told the store about itself, and the other listings that told it the same thing.

Publisher
Yuriy Yazlovytskyy
Declared legal entity
Logical Pure Minds SRL

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

Publishers can request a review.

Findings

LinkMatch Insightly uploads LinkedIn API responses to LinkMatch as you browse

Code analysis shows LinkedIn profile, inbox and Sales Navigator data is copied from page requests and posted to app2.linkmatch.com without a save click.

Severity
High unwanted
Type
Unexpected
CWE
CWE-359
Source
Static analysis
What actually happens
You did this

You open a LinkedIn profile, inbox thread or Sales Navigator list.

The page makes its normal internal API calls.

The extension did this

The extension copies the API response and uploads it to app2.linkmatch.com.

No save or click is needed before the upload.

The code that does this

Page-world fetch wrapper that copies LinkedIn API responses

Readable version

Relay helper

main-world-script-bundle.js
const oe = (n, r, t, s, f) => {    const i = n || window,      c = n ? "iframe" : "window";    i.postMessage({      type: "REQ_RESPONSE",      response: r,      request: {        headers: s || {}      },      url: t,      source: c,      iframeId: f || null    }, "*")  }

fetch wrapper

main-world-script-bundle.js
Ae = (n, r) => {    const t = n || window,      s = t.fetch;    t.fetch = (...f) => ne(void 0, void 0, void 0, function*() {      const [i, c] = f, b = typeof i == "string" ? i : i.url;      if (!W(b)) return s(i, c);      try {        let h = {};        typeof i == "string" ? c != null && c.headers && new Headers(c.headers).forEach((q, v) => {          h[v] = q        }) : i.headers.forEach((k, q) => {          h[q] = k        });        const C = yield s(i, c), d = yield C.clone().json();        return oe(n, d.data || d, b, h, r), C      } catch (h) {        return s(i, c)      }    })  }
LinkedIn endpoints whose responses are captured (content script URL patterns)
  • Profile and contact info
    voyager/api/graphql(...)&queryId=voyagerIdentityDashProfiles

    Profile details and contact details for people you view.

  • Inbox
    voyagerMessagingGraphQL/graphql?queryId=messengerMessages

    Message and conversation data from your LinkedIn inbox.

  • Sales Navigator
    sales-api/salesApiLeadSearch?q

    Lead, account and messaging thread data from Sales Navigator.

  • Recruiter
    talent/search/api/talentRecruiterSearchHits

    Candidate profiles, conversations and search hits from Recruiter.

The code that does this

Content script listener and upload function

Readable version

Listener for REQ_RESPONSE messages

content-script-bundle.js
const e = r => {  var o;  if (((o = r.data) === null || o === void 0 ? void 0 : o.type) === "REQ_RESPONSE") {    const i = r.data;    R7e(i.url, i.response, i.request)  }};window.addEventListener("message", e, !1)

Upload to LinkMatch

content-script-bundle.js
qG = (e, t) => {  let r = `${xt.linkmatch_host2}/api/s_data`;  return q0().then(o => o.caseOf({    just: i => Ja(r, {      data: Mi({        user_id: i.email,        data: e,        type: t,        s: i.s,        app: xt.ats      })    }, "application/json").then(b => b.caseOf({      left: w => (Ci({ type: "interception_error", params: { message: "Error caching data", error: w, reqType: e.reqType } }), { success: !1 }),      right: w => w    })),    nothing: () => Promise.resolve({ success: !1 })  }))}
Where the captured data is sent
    • app2.linkmatch.com

    LinkMatch backend (linkmatch_host2 production value); receives POST /api/s_data.

Observation

Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.

Where it sends data

Destinations our analysis observed LinkMatch for Insightly contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.

  • app2.linkmatch.com

    LinkMatch for Insightly sends data to app2.linkmatch.com. 6 other extensions we have analysed send data here.

Updated 15 October 2026edecojondonpbepnjhjdcgkkikfmaedk