Is 壹伴 · 小插件 safe?

High risk

壹伴 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.…

nightingales-developersv12.3.16Chrome Web Store
75Risk

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

Publishers can request a review.

Findings

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-829
SourceAI SANDBOX

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.

01EvidenceCAUSE EFFECT
What actually happens
You did this

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.

The extension did this

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.

02EvidenceNETWORK CAPTURE
Captured request
GEThttps://yiban.io/extension/proxy.pac
200 OK response observed; the PAC response body was not recorded in the evidence text.
03EvidenceFIELD TABLE
Fields affected by the proxy-control path
FieldValueWhy 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.comA 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.
04EvidenceCODE COMPARE
The code that does this

UpgradeProxy fetches a PAC script and can install it with chrome.proxy.settings.set

What it actually does
Readable checkNeedUpgrade() fetches yiban.io/extension/proxy.pacbackground-script.js
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(() => {})
}
Readable initProxy() checks Chrome proxy control before applying PACbackground-script.js
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)
  }
}
Readable addProxyConfigs() calls chrome.proxy.settings.setbackground-script.js
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()
  })
}
Parsed manifest permissionsmanifest.json
{
  "permissions": [
    "sidePanel",
    "tabs",
    "storage",
    "unlimitedStorage",
    "cookies",
    "notifications",
    "contextMenus",
    "webRequest",
    "proxy",
    "alarms",
    "declarativeNetRequestWithHostAccess",
    "declarativeNetRequestFeedback"
  ],
  "host_permissions": [
    "<all_urls>"
  ]
}
05EvidenceTHIRD PARTY LIST
External hosts in this proxy path
  • 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.

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

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.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You open the 壹伴 popup or interact with a UI feature.

The extension did this

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.

02EvidenceNETWORK CAPTURE
Captured request
POSThttps://api.yiban.io/user/use_func
HTTP 200 OK. Captured as request ID 1422419.103 by the background service worker on popup open.
Body
{
  "action": "插件打开popup",
  "extension_version": "12.1.0",
  "data": {}
}
03EvidenceNETWORK CAPTURE
Captured request
POSThttps://api.yiban.io/user/behavior/add
HTTP 200 OK. Captured as request ID 1422419.38 by the background service worker on popup open.
Body
{
  "func_type": "click",
  "func_page": "entrance",
  "func_name": "popup_bar",
  "client_version": "12.1.0"
}
04EvidenceFIELD TABLE
Fields sent to api.yiban.io/user/use_func:
FieldValueWhy it matters
Action name
插件打开popupA label describing what you did inside the extension, written in Chinese.
Extension version
12.1.0Which version of 壹伴 you have installed.
Action data
{}Optional structured data accompanying the action. Contents depend on which feature you used.
05EvidenceFIELD TABLE
Fields sent to api.yiban.io/user/behavior/add (authenticated session):
FieldValueWhy it matters
UI element type
clickCategory of the UI interaction (e.g. 'click').
UI page
entranceWhich screen of the extension you were on.
UI element name
popup_barThe specific element you interacted with.
WeChat account ID (mpId)
gh_a3b2c1d4e5f6Your 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.0Which version of 壹伴 you have installed.
06EvidenceCODE COMPARE
The code that does this

The Gn tracker class that wraps all UI event reporting.

What it actually does
Gn tracker class
// 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);
    }
  }
}
API stubs
// 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);
}
07EvidenceTHIRD PARTY LIST
Where interaction telemetry is sent:
  • 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.

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

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.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You install 壹伴 and open your browser.

The extension did this

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.

02EvidenceNETWORK CAPTURE
Captured request
POSThttps://api.yiban.io/user/report/screen_size
HTTP 200 OK. Captured as request ID 1422419.20 by the background service worker on extension startup with no user interaction.
Body
{
  "width": 1280,
  "height": 1024
}
03EvidenceFIELD TABLE
What 壹伴 sends to api.yiban.io/user/report/screen_size:
FieldValueWhy it matters
Screen width
1280The pixel width of your monitor as reported by your browser.
Screen height
1024The pixel height of your monitor as reported by your browser.
04EvidenceCODE COMPARE
The code that does this

The content script reads screen dimensions and stores them; the background worker posts them daily.

What it actually does
Content-script: read screen dimensions and store
// 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 {}
}
Background: post once per calendar day
// 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 });
  }
}
API layer
// Wraps the actual fetch POST call
function reportUserScreenSize(payload) {
  return post('/user/report/screen_size', {}, payload);
}
05EvidenceTHIRD PARTY LIST
Where screen dimension data is sent:
  • 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).

Updated 17 September 2026ibefaeehajgcpooopoegkifhgecigeeg