Is 穿梭Transocks回国加速器 - 海外华人回国追剧听歌 safe?
穿梭 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.…
Who publishes it穿梭 Transocks.com - no other listings under this identity
穿梭 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
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.
You install or launch your browser with Transocks active.
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.
The canvas fingerprinting function from the extension's shipped source
// 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);
});// 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)
});
// ...
};| Content-Type | application/json |
{
"encrypted": "1CkbVlkb7E+S7ksPgA6oyoZ83OvjG9IGnLDpI0Gsyh3siEK+1iULcplYW2C6Bb6SmyZD31ZLyuCOtO1X0e+BdFnD/NP5yMLWES7tmwP32DoGWhcFKMUOSez1lSBMmwRYx9AYp7CMLH35+mPqAmKLQeMUJO0YzOaz9ZKoGk/9xjKdLoQNmp50c3p2YGl3vHG4",
"t": 1776495503,
"sign": "Mwuf91R3fZlWTctpBYZ52dTfYw4=",
"version": 1811,
"pub_key": "ikobbjiomdcedikdmkfhlhoagpailcbh"
}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.
{
"target": "links",
"device": "chrome",
"mac": "84ccbd751f5160b9915d2f8683eea69ceef4b4a6900a260354fee430b056c415",
"org": "transocks_pro"
}| Field | Value | Why it matters | |
|---|---|---|---|
Canvas device fingerprint | 84ccbd751f5160b9915d2f8683eea69ceef4b4a6900a260354fee430b056c415 | A 64-character hash from how your GPU and fonts render a fixed test image. Stable across restarts and reinstalls; a persistent identifier. | |
Browser type | chrome | Identifies that you are using Chrome. | |
App identifier | transocks_pro | Hardcoded string that tags every request as coming from the Transocks Pro Chrome extension. | |
Request target | links | Tells the server which data endpoint is being requested (e.g. links, route-info, callingcodes). |
- 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.
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.
// 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));
- 1Open Chrome DevTools on any page with Transocks installed.
- 2Go to Network tab and find a POST to webapi.fobwifi.com.
- 3Copy the full request body JSON.
- 4Paste it into capturedBody in this script.
- 5Run: node transocks-decrypt.js
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.
You sign in to the Transocks popup with an email, phone number, and password.
The extension combines those credentials with browser, device, app, language, organization, and fingerprint fields before posting to its backend.
| Field | Value | Why 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. |
Login fields and backend request path in the shipped popup bundle
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(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
})
}))
} 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
}))
} 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,- 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.
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.
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 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.
| Field | Value | Why 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.4 | Shows which installed extension build produced the diagnostic record. | |
VPN event type | proxy_error | Describes 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. |
Service worker log construction and offscreen SLS sender
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) {}
}
}))
} 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
}
})- 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