Is 穿梭Transocks回国加速器 - 海外华人回国追剧听歌 safe?

High risk

穿梭 Transocks is high risk. On load, Transocks hashes an invisible canvas into a device fingerprint ('mac'), sent in every request to webapi.fobwifi.com. Derived from GPU/font rendering, stable across reinstalls; 9 captured requests shared the same mac.…

穿梭 Transocks.comv3.4.0Chrome Web Store
75Risk
Who publishes it

穿梭 Transocks.com - no other listings under this identity

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

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

Canvas Fingerprint Sent as Persistent Device ID on Every Request

On load, Transocks hashes an invisible canvas into a device fingerprint ('mac'), sent in every request to webapi.fobwifi.com.

Derived from GPU/font rendering, stable across reinstalls; 9 captured requests shared the same mac.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You install or launch your browser with Transocks active.

The extension did this

The extension renders an invisible canvas image, hashes the pixel output, and sends the hash as a device identifier to webapi.fobwifi.com on every API call.

No user interaction is required. The fingerprint is computed once and cached, then attached to every subsequent request without a consent prompt.

02EvidenceCODE COMPARE
The code that does this

The canvas fingerprinting function from the extension's shipped source

What it actually does
Canvas fingerprint function
// Generates a device fingerprint by drawing a fixed image on an invisible canvas
// and hashing the resulting PNG pixels. GPU and font-rendering differences
// cause the pixel output to vary across machines and OSes.
const computeCanvasFingerprint = () => new Promise((resolve, reject) => {
  const canvas = new OffscreenCanvas(200, 20);
  const ctx = canvas.getContext('2d');
  const testString = 'i9asdm..$#po((^@KbXrww!~cz';

  // Fixed drawing sequence — identical on every run on the same hardware
  ctx.textBaseline = 'alphabetic';
  ctx.font = "16px 'Arial'";
  ctx.rotate(0.05);
  ctx.fillStyle = '#f60';
  ctx.fillRect(125, 1, 62, 20);
  ctx.fillStyle = '#069';
  ctx.fillText(testString, 2, 15);
  ctx.fillStyle = 'rgba(102, 200, 0, 0.7)';
  ctx.fillText(testString, 4, 17);
  ctx.shadowBlur = 10;
  ctx.shadowColor = 'blue';
  ctx.fillRect(-20, 10, 234, 5);

  canvas.convertToBlob().then(blob => {
    const reader = new FileReader();
    reader.readAsDataURL(blob);
    reader.onloadend = () => {
      const base64png = reader.result.split(',')[1];
      const fingerprint = sha256(base64png); // 64-char hex string
      resolve(fingerprint);
    };
  }).catch(reject);
});
First API call attaching the fingerprint
// On startup, assemble a payload that includes the canvas fingerprint as 'mac'
// and POST it to the server. This same fingerprint appears in every subsequent request.
const fetchLinks = async (domain) => {
  const payload = encryptPayload({
    target: 'links',
    device: 'chrome',
    mac: await computeCanvasFingerprint(),  // persistent device ID
    org: 'transocks_pro'
  }, isExtVersion = true);
  const response = await fetch(`${domain}/ext/gateway`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload)
  });
  // ...
};
03EvidenceNETWORK CAPTURE
Captured request
POSThttps://webapi.fobwifi.com/ext/gateway
Encrypted response body; decrypts to server-provided link list
Headers
Content-Typeapplication/json
Body
{
  "encrypted": "1CkbVlkb7E+S7ksPgA6oyoZ83OvjG9IGnLDpI0Gsyh3siEK+1iULcplYW2C6Bb6SmyZD31ZLyuCOtO1X0e+BdFnD/NP5yMLWES7tmwP32DoGWhcFKMUOSez1lSBMmwRYx9AYp7CMLH35+mPqAmKLQeMUJO0YzOaz9ZKoGk/9xjKdLoQNmp50c3p2YGl3vHG4",
  "t": 1776495503,
  "sign": "Mwuf91R3fZlWTctpBYZ52dTfYw4=",
  "version": 1811,
  "pub_key": "ikobbjiomdcedikdmkfhlhoagpailcbh"
}
04EvidenceOPAQUE REVEAL
Why you can't catch this in DevTools

Every request body sent to webapi.fobwifi.com is AES-256-CBC encrypted. In your browser's DevTools Network tab the payload is unreadable. Because the encryption key is hardcoded in the extension's source, the full plaintext can be recovered, as shown here for the first startup request.

What's actually being sent
{
  "target": "links",
  "device": "chrome",
  "mac": "84ccbd751f5160b9915d2f8683eea69ceef4b4a6900a260354fee430b056c415",
  "org": "transocks_pro"
}
05EvidenceFIELD TABLE
What the decrypted 'links' request body contains:
FieldValueWhy it matters
Canvas device fingerprint
84ccbd751f5160b9915d2f8683eea69ceef4b4a6900a260354fee430b056c415A 64-character hash from how your GPU and fonts render a fixed test image. Stable across restarts and reinstalls; a persistent identifier.
Browser type
chromeIdentifies that you are using Chrome.
App identifier
transocks_proHardcoded string that tags every request as coming from the Transocks Pro Chrome extension.
Request target
linksTells the server which data endpoint is being requested (e.g. links, route-info, callingcodes).
06EvidenceTHIRD PARTY LIST
Where the fingerprint is sent:
  • webapi.fobwifi.com

    Primary API server for Transocks. Receives every encrypted request including the canvas fingerprint on startup and all subsequent API calls.

  • b.kolavpn.xyz

    Fallback API domain listed in the extension source as a retry target if webapi.fobwifi.com is unreachable.

07EvidenceARTIFACT
Reproduce it yourself

Decrypts captured Transocks request bodies from your browser's DevTools. Paste an encrypted request body (the JSON object with 'encrypted', 't', 'sign' fields) and the script prints the plaintext payload including the canvas fingerprint.

RequiresNode.js 18+
transocks-decrypt.js · js
// transocks-decrypt.js
// Decrypts Transocks API request bodies using the hardcoded key.
// Run: node transocks-decrypt.js

const crypto = require('crypto');

const EXT_ID = 'ikobbjiomdcedikdmkfhlhoagpailcbh';
const HARDCODED_KEY_SUFFIX = 'tZn7uJwcHjAJr4fQ3';

// Paste any captured request body here (copy from DevTools → Network → Request Payload)
const capturedBody = {
  "encrypted": "1CkbVlkb7E+S7ksPgA6oyoZ83OvjG9IGnLDpI0Gsyh3siEK+1iULcplYW2C6Bb6SmyZD31ZLyuCOtO1X0e+BdFnD/NP5yMLWES7tmwP32DoGWhcFKMUOSez1lSBMmwRYx9AYp7CMLH35+mPqAmKLQeMUJO0YzOaz9ZKoGk/9xjKdLoQNmp50c3p2YGl3vHG4",
  "t": 1776495503,
  "sign": "Mwuf91R3fZlWTctpBYZ52dTfYw4=",
  "version": 1811,
  "pub_key": "ikobbjiomdcedikdmkfhlhoagpailcbh"
};

function decryptBody(body) {
  const r = EXT_ID + HARDCODED_KEY_SUFFIX;
  const a = String(body.t).slice(-8);

  // AES key derivation
  const keyBytes = crypto.createHash('sha256').update(r + a).digest();

  // IV derivation
  const ivInput = Buffer.concat([keyBytes, Buffer.from(r + a)]);
  const ivBytes = crypto.createHash('sha256').update(ivInput).digest().slice(0, 16);

  // Decrypt
  const ciphertext = Buffer.from(body.encrypted, 'base64');
  const decipher = crypto.createDecipheriv('aes-256-cbc', keyBytes, ivBytes);
  decipher.setAutoPadding(true);
  const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
  return JSON.parse(plaintext.toString('utf-8'));
}

console.log('Decrypted payload:');
console.log(JSON.stringify(decryptBody(capturedBody), null, 2));
How to run it
  1. 1
    Open Chrome DevTools on any page with Transocks installed.
  2. 2
    Go to Network tab and find a POST to webapi.fobwifi.com.
  3. 3
    Copy the full request body JSON.
  4. 4
    Paste it into capturedBody in this script.
  5. 5
    Run: node transocks-decrypt.js
SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-200
SourceAI SANDBOX

Transocks Login Sends Credentials with Device Fingerprint

Signing in with email or phone makes the extension add your password, OS/browser version, app version, language, org tag, device type, and a canvas fingerprint to a POST to webapi.fobwifi.com/ext/gateway; the body was AES-CBC encrypted.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You sign in to the Transocks popup with an email, phone number, and password.

The extension did this

The extension combines those credentials with browser, device, app, language, organization, and fingerprint fields before posting to its backend.

02EvidenceFIELD TABLE
Plaintext fields assembled before request encryption
FieldValueWhy it matters
Your Transocks account identifier
alice@example.com (illustrative)This identifies the account you are trying to sign in to.
Your Transocks password
S7v9-River-Lantern-42 (illustrative)This is the password you typed into the login form.
Your operating-system string
X11; Linux x86_64 (illustrative)This describes the platform details exposed by your browser.
Your browser version
120.0.6099.129 (illustrative)This records the browser version parsed from your user-agent string.
Your canvas-derived fingerprint
8f14e45fceea167a5a36dedd4bea2543f9c0a1b2c3d4e5f60718293a4b5c6d7e (illustrative)This gives the backend a stable device signal computed from how your browser renders a canvas.
Extension and service context
device=chrome, org=transocks_pro, app_version=3.4.4, language=en (illustrative)This tells the backend which extension build, device family, organization tag, and language setting sent the request.
Existing access token when present
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0In0.XyZ9bR2p0nQ4mV6aS8dT1uF3kL5wC7eH0jPq (illustrative)If you are already signed in, this can link the request to an existing session.
03EvidenceNETWORK CAPTURE
Captured request
POSThttps://webapi.fobwifi.com/ext/gateway
Dynamic analysis observed encrypted POST traffic to this endpoint, including a new POST after a login click; plaintext login fields were not readable from the wire body.
04EvidenceCODE COMPARE
The code that does this

Login fields and backend request path in the shipped popup bundle

What it actually does
Email and phone login handlersjs/popup.js
      login(e, t) {
        var n, r;
        return Kt(this, void 0, void 0, (function*() {
          const i = navigator.userAgent,
            o = i.split("(")[1].split(")")[0],
            a = i.split(")")[2].split(" ")[1].split("/")[1],
            l = yield this.extFetch({
              email: e,
              password: t,
              autokick: 1,
              auth_type: "jwt",
              auth: "email",
              app_version: gt.version,
              model: o,
              os: a
            }, "login");
          return (null === (r = null === (n = l) || void 0 === n ? void 0 : n.token) || void 0 === r ? void 0 : r.access_token) && (document.cookie = `ABS_FOBWIFISS=${l.token.access_token}`), Ne.dispatch({
            type: ve,
            value: l
          }), this.getLines(), yield this.getLinks(!0), l
        }))
      }
      loginPhone(e, t, n) {
        var r, i;
        return Kt(this, void 0, void 0, (function*() {
          const o = navigator.userAgent,
            a = o.split("(")[1].split(")")[0],
            l = o.split(")")[2].split(" ")[1].split("/")[1],
            c = yield this.extFetch({
              phone: e,
              cc: t,
              password: n,
              autokick: 1,
              auth_type: "jwt",
              auth: "mobile",
              app_version: gt.version,
              model: a,
              os: l
            }, "login");
          return (null === (i = null === (r = c) || void 0 === r ? void 0 : r.token) || void 0 === i ? void 0 : i.access_token) && (document.cookie = `ABS_FOBWIFISS=${c.token.access_token}`), Ne.dispatch({
            type: ve,
            value: c
          }), this.getLines(), yield this.getLinks(!0), c
        }))
      }
extFetch assembles and encrypts the request bodyjs/popup.js
      extFetch(e, t, n) {
        var r, i;
        return Kt(this, void 0, void 0, (function*() {
          const o = yield Se.asyncLocalGet([ve]), {
            language: a
          } = yield Se.asyncLocalGet([ke]), l = o.user_info, c = yield at();
          n && n();
          const s = {
            target: t,
            device: ft,
            mac: c,
            org: "transocks_pro",
            app_version: gt.version,
            language: a.language
          };
          e.langue || Object.assign(s, e), (null === (i = null === (r = l) || void 0 === r ? void 0 : r.token) || void 0 === i ? void 0 : i.access_token) && (s.access_token = l.token.access_token);
          const u = ct(s, null, !0),
            f = e.langue ? Object.assign(Object.assign({}, u), {
              langue: e.langue
            }) : u,
            d = yield zt("/ext/gateway", {
              method: "POST",
              body: f
            }, !1, !0, {
              retryOnFail: "login" === t
            });
          return Object.assign(Object.assign({}, d.data), {
            status: d.status,
            code: d.code
          })
        }))
      }
zt serializes POST bodies and sends them to the selected backend hostjs/popup.js
  function zt(e, t, n = !0, r = !1, i = {}) {
    var o, a, l, c;
    return Bt(this, void 0, void 0, (function*() {
      const s = yield at(), u = yield Ot();
      if ("GET" === t.method && n) {
        const t = `org=${ut}&mac=${s}&device=${ft}`; - 1 !== e.indexOf("?") ? e += `&${t}` : e += `?${t}`
      }
      const f = Object.assign({
          credentials: "include"
        }, t),
        d = (yield Se.asyncLocalGet([ve])).user_info;
      (null === (a = null === (o = d) || void 0 === o ? void 0 : o.token) || void 0 === a ? void 0 : a.token_type) && (null === (c = null === (l = d) || void 0 === l ? void 0 : l.token) || void 0 === c ? void 0 : c.access_token) && (f.headers = Object.assign({
        Authorization: `${d.token.token_type} ${d.token.access_token}`
      }, f.headers)), "POST" !== f.method && "PUT" !== f.method && "DELETE" !== f.method || (f.headers = Object.assign({
        Accept: "application/json",
        "Content-Type": "application/json; charset=utf-8"
      }, f.headers), n && (f.body = Object.assign({
        mac: s,
        device: ft,
        org: ut
      }, f.body)), f.body = JSON.stringify(f.body));
      const h = i.retryOnFail ? [...new Set([u, ht, ...pt])] : [u];
      let p;
      for (let t = 0; t < h.length; t++) {
        const n = h[t];
        try {
          const t = yield Tt(fetch(`${n}${e}`, f).then(Mt).then(e => Rt(e, f.method, r)));
          return n !== u && Se.localSet({
            domain: n
          }), t
        } catch (e) {
          if (p = e, !i.retryOnFail || (m = e) && "request timeout" !== m.message && m.status && !(m.status >= 500)) throw e
        }
      }
      var m;
      throw p
    }))
  }
Canvas hash and AES-CBC request wrapperjs/popup.js
    at = () => $e(void 0, void 0, void 0, (function*() {
      return new Promise((e, t) => {
        const n = new OffscreenCanvas(200, 20),
          r = n.getContext("2d"),
          i = "i9asdm..$#po((^@KbXrww!~cz";
        r.textBaseline = "top", r.font = "16px 'Arial'", r.textBaseline = "alphabetic", r.rotate(.05), r.fillStyle = "#f60", r.fillRect(125, 1, 62, 20), r.fillStyle = "#069", r.fillText(i, 2, 15), r.fillStyle = "rgba(102, 200, 0, 0.7)", r.fillText(i, 4, 17), r.shadowBlur = 10, r.shadowColor = "blue", r.fillRect(-20, 10, 234, 5), n.convertToBlob().then(t => {
          const n = new FileReader;
          n.readAsDataURL(t), n.onloadend = () => {
            const t = n.result.split(",")[1],
              r = Object(Qe.sha256)(t);
            e(r)
          }
        }).catch(e => {
          t(e)
        })
      })
    }));

  function ct(e, t, n = !1) {
    let r, i;
    t ? (i = vt, r = i + yt) : n && (i = vt, r = i + yt);
    const o = JSON.stringify(e),
      a = Math.floor(Date.now() / 1e3),
      l = a.toString().slice(-8),
      c = new Uint8Array(Qe.sha256.arrayBuffer(Ke(r + l))),
      s = new Uint8Array(Qe.sha256.arrayBuffer(Je(c, Ke(r + l)))).slice(0, 16),
      u = Ye(new We.a.ModeOfOperation.cbc(c, s).encrypt(Le.padding.pkcs7.pad(Ke(o))));
    let f = `encrypted=${u}&pub_key=${i}&t=${a}`;
    n && (f += `&version=${bt}`);
    const d = {
      encrypted: u,
      t: a,
      sign: Ye(Ge(Object(Fe.HmacSHA1)(f, r).toString()))
    };
    return n && (d.version = bt, d.pub_key = i), d
  }

  function st() {
    return !!navigator.userAgent.includes("Edg/")
  }
  const ut = "transocks_pro",
    ft = st() ? "edge" : "chrome",
    dt = st() ? `https://microsoftedge.microsoft.com/addons/detail/${chrome.runtime.id}` : `https://chrome.google.com/webstore/detail/${chrome.runtime.id}`,
    ht = "https://webapi.fobwifi.com",
    pt = ["https://b.kolavpn.xyz"],
    mt = "https://www.transocks.com.cn/",
    gt = chrome.runtime.getManifest(),
    vt = chrome.runtime.id,
    yt = "tZn7uJwcHjAJr4fQ3",
    bt = 1811,
05EvidenceTHIRD PARTY LIST
Backend hosts reachable from this login flow
  • webapi.fobwifi.com

    Primary Transocks API host receiving /ext/gateway login and startup requests.

  • b.kolavpn.xyz

    Fallback API host listed in the same popup bundle retry list.

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-319
SourceAI SANDBOX

VPN telemetry sent as plaintext JSON to Alibaba Cloud SLS

After VPN checks or proxy errors, the extension builds a diagnostic log (Transocks account ID, app version, user agent, VPN mode, line, error details), relayed to an offscreen doc posting JSON to Alibaba Cloud SLS.

No live request captured.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You try to connect the VPN, or an active proxy connection reports an error.

The relevant code path is reached from connectivity-test and proxy-error handling.

The extension did this

The extension assembles a diagnostic record and hands it to an offscreen page for delivery to Alibaba Cloud SLS.

The record includes stored account context and VPN error details when those values are present.

02EvidenceFIELD TABLE
Fields assembled before the SLS send
FieldValueWhy it matters
Transocks account ID
12345678 (illustrative)Lets the diagnostic event be tied to the Transocks account stored by the extension.
Browser and device string
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 (illustrative)Shows browser and operating-system context alongside the VPN event.
Extension version
3.4.4Shows which installed extension build produced the diagnostic record.
VPN event type
proxy_errorDescribes whether the log came from a connectivity check failure or a proxy error.
VPN mode and selected line
mode: proxy; connect_line: Hong Kong 01 (illustrative)Adds the VPN operating mode and the selected route or server name to the diagnostic event.
Error details
{"domain":"https://www.baidu.com","status":407} (illustrative)Records the failed connectivity target, proxy error, or HTTP status that triggered the diagnostic event.
03EvidenceNETWORK CAPTURE
Captured request
POSThttps://transocks-client-3.ap-northeast-1.log.aliyuncs.com/logstores/chrome/track?APIVersion=0.6.0
No live SLS request was captured; unauthenticated sessions did not reach the VPN connect or proxy-error trigger.
04EvidenceCODE COMPARE
The code that does this

Service worker log construction and offscreen SLS sender

What it actually does
Readable service-worker log relaybackground.js
  const Se = new Map;
  let ke;
  const Ae = () => we(void 0, void 0, void 0, (function*() {
    const e = chrome.runtime.getURL("offscreen.html");
    return (yield chrome.runtime.getContexts({
      contextTypes: ["OFFSCREEN_DOCUMENT"],
      documentUrls: [e]
    })).length > 0
  }));

  function xe(e) {
    return we(this, void 0, void 0, (function*() {
      yield function(e) {
        return we(this, void 0, void 0, (function*() {
          (yield Ae()) || (ke ? yield ke: (ke = chrome.offscreen.createDocument({
            url: e,
            reasons: ["DOM_PARSER"],
            justification: "Parse and send log data to Alibaba Cloud SLS via DOM-based SDK"
          }), yield ke))
        }))
      }("offscreen.html"), (yield Ae()) && (yield chrome.runtime.sendMessage({
        type: "SLS_SEND_LOG",
        target: "offscreen",
        data: e
      }))
    }))
  }

  function Ee(e) {
    var t;
    return we(this, void 0, void 0, (function*() {
      const n = function(e) {
          const {
            timestamp: t
          } = e, n = be(e, ["timestamp"]);
          return JSON.stringify(n)
        }(e),
        r = Date.now();
      Se.size > 50 && function() {
        const e = Date.now();
        for (const [t, n] of Se) e - n >= 6e4 && Se.delete(t)
      }();
      const i = Se.get(n);
      if (!(i && r - i < 6e4)) {
        Se.set(n, r);
        try {
          yield function() {
            var e;
            return we(this, void 0, void 0, (function*() {
              const t = (yield f.asyncLocalGet(["sls_sts_config"])).sls_sts_config;
              if (1e3 * (null === (e = t) || void 0 === e ? void 0 : e.ExpireAt) > Date.now()) return t;
              const n = yield me.extFetch({
                scope: "log_access"
              }, "sts");
              if (!n || !n.AccessKeyId) throw new Error("Failed to get STS config");
              const r = {
                AccessKeyId: n.AccessKeyId,
                AccessKeySecret: n.AccessKeySecret,
                SecurityToken: n.SecurityToken,
                ExpireAt: n.ExpireAt
              };
              return f.localSet({
                sls_sts_config: r
              }), r
            }))
          }();
          const n = yield f.asyncLocalGet([a]);
          yield xe(Object.assign({
            user_id: null === (t = n.user_info) || void 0 === t ? void 0 : t.transocks_id,
            app_version: $.version,
            device: navigator.userAgent
          }, e))
        } catch (e) {}
      }
    }))
  }
Readable offscreen SLS senderjs/offscreen.js
  function u(t, e) {
    const r = new window.XMLHttpRequest;
    r.open("POST", `${t}?APIVersion=0.6.0`, !0), r.send(e)
  }

  function h(t, e) {
    try {
      if (e.length >= 32768) return void u(t, e);
      (function(t, e) {
        return !(!navigator || !navigator.sendBeacon) && navigator.sendBeacon(`${t}?APIVersion=0.6.0`, e)
      })(t, e) || u(t, e)
    } catch (e) {
      window && window.console && "function" == typeof window.console.error && (console.error("Failed to log to ali log service because of this exception:\n" + e), console.error("Failed log data:", t))
    }
  }
  class d extends class {
    constructor(t) {
      var e, r, n;
      this.timer = null, this.time = 10, this.count = 10, this.arr = [], this.time = null != (e = t.time) ? e : 10, this.count = null != (r = t.count) ? r : 10, this.ccController = new o(null != (n = t.maxReqCount) ? n : 10), t.host.startsWith("http://") || t.host.startsWith("https://") ? this.url = t.host + "/logstores/" + t.logstore + "/track" : this.url = "https://" + t.project + "." + t.host + "/logstores/" + t.logstore + "/track", this.opt = t, t.installUnloadHook && "function" == typeof t.installUnloadHook && t.installUnloadHook(() => {
        this.sendImmediateInner()
      })
    }
    assemblePayload(t) {
      const e = {
        __logs__: t
      };
      return this.opt.tags && (e.__tags__ = this.opt.tags), this.opt.topic && (e.__topic__ = this.opt.topic), this.opt.source && (e.__source__ = this.opt.source), JSON.stringify(e)
    }
    platformSend() {
      if (this.opt.sendPayload && "function" == typeof this.opt.sendPayload) {
        const t = this.assemblePayload(this.arr);
        this.ccController.append(() => this.opt.sendPayload(this.url, t))
      }
    }
    transString(t) {
      let e = {};
      for (let r in t) "object" == typeof t[r] ? e[r] = JSON.stringify(t[r]) : e[r] = String(t[r]);
      return e
    }
    sendImmediateInner() {
      this.arr && this.arr.length > 0 && (this.platformSend(), null != this.timer && (clearTimeout(this.timer), this.timer = null), this.arr = [])
    }
    sendInner() {
      if (this.timer) this.arr.length >= this.count && (clearTimeout(this.timer), this.timer = null, this.sendImmediateInner());
      else {
        const t = this;
        this.arr.length >= this.count || this.time <= 0 ? this.sendImmediateInner() : this.timer = setTimeout((function() {
          t.sendImmediateInner()
        }), 1e3 * this.time)
      }
    }
    send(t) {
      const e = this.transString(t);
      this.arr.push(e), this.sendInner()
    }
    sendImmediate(t) {
      const e = this.transString(t);
      this.arr.push(e), this.sendImmediateInner()
    }
    sendBatchLogs(t) {
      const e = t.map(t => this.transString(t));
      this.arr.push(...e), this.sendInner()
    }
    sendBatchLogsImmediate(t) {
      const e = t.map(t => this.transString(t));
      this.arr.push(...e), this.sendImmediateInner()
    }
    overwriteTransString(t) {
      this.transString = t.transString
    }
    getOpt() {
      return this.opt
    }
  } {
    constructor(t) {
      super(Object.assign({}, t, {
        installUnloadHook: t => {
          window.addEventListener("beforeunload", () => {
            t()
          })
        },
        sendPayload: (t, e) => l(this, null, (function*() {
          h(t, e)
        }))
      }))
    }
    useStsPlugin(t) {
      this.getOpt().sendPayload = (e, r) => l(this, null, (function*() {
        yield function(t, e, r) {
          return l(this, null, (function*() {
            return new Promise(n => l(this, null, (function*() {
              try {
                t = t.slice(0, -6);
                const {
                  data: o,
                  header: s
                } = yield r.process(t, e), i = new window.XMLHttpRequest;
                i.open("POST", t, !0);
                for (let t in s) i.setRequestHeader(t, s[t]);
                i.onreadystatechange = () => {
                  4 === i.readyState && (200 === i.status || window && window.console && "function" == typeof window.console.error && (console.error("Failed to log to ali log service because of this exception:\n" + i.status), console.error("Failed logdata:", t)), n())
                }, i.send(o)
              } catch (e) {
                window && window.console && "function" == typeof window.console.error && (console.error("Failed to log to ali log service because of this exception:\n" + e), console.error("Failed log data:", t))
              }
            })))
          }))
        }(e, r, t)
      })), this.overwriteTransString(t)
    }
  }
  s = window, i = "SLS_Tracker", a = d, c ? c(() => {
    n(s, i, a)
  }) : n(s, i, a);
  const p = new d({
    host: "ap-northeast-1.log.aliyuncs.com",
    project: "transocks-client-3",
    logstore: "chrome"
  });
  chrome.runtime.onMessage.addListener((t, e, r) => {
    if ("offscreen" === t.target) {
      if ("SLS_SEND_LOG" === t.type) try {
        p.sendImmediate(t.data), r({
          success: !0
        })
      } catch (t) {
        r({
          success: !1,
          error: String(t)
        })
      }
      return !0
    }
  })
05EvidenceTHIRD PARTY LIST
External destination configured by the extension
  • transocks-client-3.ap-northeast-1.log.aliyuncs.com

    Alibaba Cloud SLS endpoint configured in js/offscreen.js; receives diagnostic log batches for project transocks-client-3 and logstore chrome.

+2 more findings not shown

What it can do

Permissions this extension asks for, as declared in version 3.4.0. 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 every site you visit

    http://*/*

  • Read and change your data on every secure site you visit

    https://*/*

  • Route all of your browsing through a server of its choosing

    proxy

  • Watch every request your browser makes

    webRequest

  • Store data in your browser

    storage

  • Schedule its own background tasks

    alarms

webRequestAuthProvider
Updated 30 September 2026ikobbjiomdcedikdmkfhlhoagpailcbh