Is 壹伴 · 小插件 safe?
壹伴 is high risk. The extension requests https://yiban.io/extension/proxy.pac at startup. Source shows that when yiban.io reports a newer version, upgrade-proxy is on, and a Google check fails, the downloaded PAC script becomes Chrome's browser-wide proxy.…
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Outdated Yiban installs can load proxy rules from yiban.io
The extension requests https://yiban.io/extension/proxy.pac at startup.
Source shows that when yiban.io reports a newer version, upgrade-proxy is on, and a Google check fails, the downloaded PAC script becomes Chrome's browser-wide proxy.
The extension starts, checks the server-reported newest version, and keeps the upgrade-proxy feature enabled by default.
The proxy path depends on the installed version being older than the newest version stored from yiban.io.
It fetches a PAC script from yiban.io and can install that script as Chrome's browser-wide proxy configuration.
Applying the PAC is further gated by Chrome proxy control and a failed connectivity check to clients2.google.com.
| Field | Value | Why it matters | |
|---|---|---|---|
Page URL | https://mp.weixin.qq.com/cgi-bin/appmsg?action=edit&token=184213655&lang=zh_CN (illustrative) | The PAC rules can make routing decisions based on the sites you visit. | |
Destination host | mp.weixin.qq.com | A browser proxy configuration can route traffic for sites across your browsing session, not just the extension's own pages. | |
Request metadata | Host: mp.weixin.qq.com; User-Agent: Chrome/123.0 (illustrative) | If the PAC selects an upstream proxy, that proxy can receive connection metadata and, for non-HTTPS traffic, request headers. |
UpgradeProxy fetches a PAC script and can install it with chrome.proxy.settings.set
async checkNeedUpgrade() {
if (!this.enabled || ve.browser !== "chrome") return;
let {
newestVersion: e
} = await ne.asyncGet(["newestVersion"]), t = ve.extensionVersion;
if (!d.checkIfNeedUpdate(t, e)) return Pe.debug("already have latest version , clear proxy config"), this.clearProxyConfigs();
let n;
n = `${ke.hosts.web}/extension/proxy.pac`, fetch(n).then(s => {
if (s.status === 200) return s.text();
throw new Error("fetch pac script failed")
}).then(s => {
s && this.pacScript !== s && (Pe.debug("fetched new pac script"), this.pacScript = s), this.initProxy()
}).catch(() => {})
}async initProxy() {
if (this.pacScript) try {
Pe.debug("need update, try to reach google api"), this.checkGoogleConnectability(e => {
if (e) Pe.debug("reached google api, skip proxy setting");
else {
if (Pe.debug("can't reach google api, try use proxy"), !this.enabled) return;
chrome.proxy.settings.get({}, ({
value: t,
levelOfControl: n
}) => {
if (n === "controlled_by_this_extension") return this.addProxyConfigs();
if (n === "controllable_by_this_extension") return this.addProxyConfigs()
})
}
})
} catch (e) {
Pe.debug("can't get latest extension version, wait until next pac auto-update loop"), console.error(e)
}
}addProxyConfigs() {
let e;
e = {
mode: "pac_script",
pacScript: {
data: this.pacScript
}
}, chrome.proxy.settings.set({
value: e,
scope: "regular"
}, () => {
Pe.debug("proxy config initialized!", {
pac: this.pacScript
}), this.checkPacScriptIsValid()
})
}{
"permissions": [
"sidePanel",
"tabs",
"storage",
"unlimitedStorage",
"cookies",
"notifications",
"contextMenus",
"webRequest",
"proxy",
"alarms",
"declarativeNetRequestWithHostAccess",
"declarativeNetRequestFeedback"
],
"host_permissions": [
"<all_urls>"
]
}- yiban.io
Supplies the latest-version data and serves the PAC script at /extension/proxy.pac.
- clients2.google.com
Used as a connectivity probe before deciding whether to apply the downloaded proxy configuration.
UI Interaction Telemetry Sent to api.yiban.io on Every Action
Dynamic analysis captured POSTs to api.yiban.io/user/use_func and .../behavior/add each popup use. use_func gets the action, version, data; behavior/add gets the UI element type, page, name, plus your WeChat account ID (mpId) and nickname.
You open the 壹伴 popup or interact with a UI feature.
The extension sends your action name, extension version, and WeChat account details to api.yiban.io.
Two separate POST requests fire: one to /user/use_func with the action label and version, and one to /user/behavior/add with the UI element type, page, name, and your mpId and mpNickname.
{
"action": "插件打开popup",
"extension_version": "12.1.0",
"data": {}
}{
"func_type": "click",
"func_page": "entrance",
"func_name": "popup_bar",
"client_version": "12.1.0"
}| Field | Value | Why it matters | |
|---|---|---|---|
Action name | 插件打开popup | A label describing what you did inside the extension, written in Chinese. | |
Extension version | 12.1.0 | Which version of 壹伴 you have installed. | |
Action data | {} | Optional structured data accompanying the action. Contents depend on which feature you used. |
| Field | Value | Why it matters | |
|---|---|---|---|
UI element type | click | Category of the UI interaction (e.g. 'click'). | |
UI page | entrance | Which screen of the extension you were on. | |
UI element name | popup_bar | The specific element you interacted with. | |
WeChat account ID (mpId) | gh_a3b2c1d4e5f6 | Your WeChat Official Account identifier. Present when you are logged in to 壹伴. | |
WeChat account nickname (mpNickname) | 我的公众号 | The display name of your WeChat Official Account. Sent alongside mpId in authenticated sessions. | |
Client version | 12.1.0 | Which version of 壹伴 you have installed. |
The Gn tracker class that wraps all UI event reporting.
// Global tracker used across the extension for all UI telemetry.
class Gn {
// Called for standard feature-use events.
// Fires to /user/use_func after a 3-second delay.
track(action, data = {}, isAdEvent = false) {
try {
if (isBackground) {
if (isAdEvent) {
setTimeout(() => {
api.trackAdEvent(action, data, extensionVersion);
}, 4000);
} else {
setTimeout(() => {
// POST {action, extensionVersion, data} to /user/use_func
api.trackUserAction(action, data, extensionVersion);
}, 3000);
}
} else {
// Content-script path: relay via message bridge to background
messageProxy.trackUserAction({ action, data, isAdEvent });
}
} catch (err) {
console.error(err);
}
}
// Called for richer behavior events.
// Fires to /user/behavior/add, enriching with mpId + mpNickname.
async trackUserEventNew(payload) {
try {
if (isBackground) {
const { mpId, mpNickname } = await this.getCurrentMpIdForBg();
const enriched = {
...payload,
remark: {
...payload.remark,
version: extensionVersion,
vip_version: userVipVersion,
mpId,
mpNickname,
},
};
storage.get(['authed'], ({ authed }) => {
// POST enriched payload to /user/behavior/add (via saveUserAction)
api.saveUserAction(enriched).preventDefault();
});
} else {
messageProxy.trackUserEventNew({ data: payload });
}
} catch (err) {
console.error(err);
}
}
}// POST {action, extensionVersion, data} to /user/use_func
function trackUserAction(action, data, extensionVersion) {
return post('/user/use_func', null, { action, extensionVersion, data }).markSilent();
}
// POST behavior object to /user/behavior/add
function trackUserEvent(payload) {
return post('/user/behavior/add', null, payload);
}- api.yiban.io
壹伴's own backend API. Receives feature-use events (/user/use_func) and detailed behavior events (/user/behavior/add) on every significant UI interaction.
Screen Dimensions Reported Daily to api.yiban.io
Dynamic analysis captured a POST to https://api.yiban.io/user/report/screen_size with screen width/height (1280x1024 in our test).
The content script reads/stores dimensions 5s after load; the background posts daily, from 30s after install.
You install 壹伴 and open your browser.
The extension reads your screen dimensions and sends them to api.yiban.io once per day.
No user action beyond installation is required. The upload fires 30 seconds after the extension first starts.
{
"width": 1280,
"height": 1024
}| Field | Value | Why it matters | |
|---|---|---|---|
Screen width | 1280 | The pixel width of your monitor as reported by your browser. | |
Screen height | 1024 | The pixel height of your monitor as reported by your browser. |
The content script reads screen dimensions and stores them; the background worker posts them daily.
// Runs 5 seconds after the content-script loads on every page (all_frames: true).
setTimeout(() => { this.recordUserScreenSize(); }, 5 * 1000);
recordUserScreenSize() {
try {
const { width, height } = window.screen;
// Writes to chrome.storage so the background can read it later
Ce.set({ userScreenSize: { width, height } });
} catch {}
}// Called 30 seconds after the extension first installs.
this.execFirstInstallCall(() => {
this.startAlarms();
this.registerHeaderModifier();
this.recordLatestUserId();
setTimeout(() => {
this.reportUserScreenSize();
}, 30 * 1000);
});
async reportUserScreenSize() {
const { userScreenSize, reportUserScreenSizeDate } = await ne.asyncGet(
['userScreenSize', 'reportUserScreenSizeDate']
);
const today = d.parseTime(Date.now(), 'y-m-d'); // e.g. '2026-04-14'
if (!reportUserScreenSizeDate || reportUserScreenSizeDate !== today) {
// POST to api.yiban.io/user/report/screen_size
oe.reportUserScreenSize(userScreenSize).preventDefault();
// Mark today so it doesn't fire again until tomorrow
ne.set({ reportUserScreenSizeDate: today });
}
}// Wraps the actual fetch POST call
function reportUserScreenSize(payload) {
return post('/user/report/screen_size', {}, payload);
}- api.yiban.io
壹伴's own backend API. Receives screen dimensions once per day per user. yiban.io is the vendor's primary domain (the extension ID prefix 'iban' matches the domain).