Is 「效率集」聚合搜索 safe?

Medium risk

「效率集」聚合搜索 fetches config from files.xiaolvji.com and lets it set network rules, open tabs and drive search-page input.

The extension downloads a remote configuration from files.xiaolvji.com and stores it. That configuration supplies declarativeNetRequest rules the extension installs on all sites, URLs it opens in background tabs during multi-search, and selectors and strings used to simulate typing and clicks on search-result pages. None of this is checked against an allowlist.

www.xiaolvji.comv9.851.69.19Chrome Web Store
58Risk
Who publishes it

www.xiaolvji.com - 1 other listing from the same operator, 1 of them carrying a finding

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

Publisher
www.xiaolvji.com

Same store account

1 other listing published from this account, 544 users between them. 1 of them carries a finding.

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

Publishers can request a review.

Findings

Server-supplied selectors drive scripted input and clicks in search tabs

Code analysis shows the extension runs bundled input-simulation scripts on search-result tabs, using targets and strings from a files.xiaolvji.com config plus your search word.

Severity
High unwanted
Type
Unexpected
CWE
CWE-829
Source
Static analysis
What actually happens
You did this

You search from the extension on an engine set to scripted input.

The engine entry comes from the stored server config.

The extension did this

The extension injects scripts that type your search word and click on the engine page.

The functions ship in the extension; their targets and strings come from the server.

Config values passed into the injected functions
  • Selectors
    input[name=q] (illustrative)

    Pick which page elements receive input or clicks.

  • Match string
    search (illustrative)

    Text pattern the script uses to find its target.

  • Your search word
    cheap flights

    Typed into the engine page by the script.

  • Frame
    0

    The frame in the tab that receives the script.

The code that does this

Config request and storage of the server-supplied lists

Readable version

Config fetch and store

js/15.js
        r = (a ? t = "plan" : o && (t = "versionUpdate"), (new Date).getTime());      fetch(g, {        method: "POST",        headers: {          "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"        },        body: new URLSearchParams({          type: e,          ctype: t,          lang: V,          version: i[V],          cver: c,          tn: r,          ssid: ce(e, r, 8)        })      }).then(e => 200 <= e.status && e.status < 300 ? Promise.resolve(e) : Promise.reject(new Error(e.statusText))).then(e => e.json()).then(e => {        var t, n = r.toString();        r % 9 == 0 && parseInt(e.msg) !== parseInt(n) % 512 && (oe.set({          iq: parseInt(n) % 2006        }), Z = !0), n = 829067 <= c ? JSON.parse(e.data) : JSON.parse(Base64.decode(e.data)), 200 === e.code ? (a ? (t = p(n.config, a), se(t.enginesData, t.userConfigData, () => {          s ? s(1) : _()        })) : (o && (n.config.userConfigData.zdy = o), se(n.config.enginesData, n.config.userConfigData, () => {          s ? s(1) : _()        })), void 0 !== n.news ? oe.set({          news: n.news        }) : oe.remove("news"), void 0 !== n.ll ? oe.set({          ll: n.ll        }) : oe.remove("ll"), void 0 !== n.xl ? oe.set({          xl: n.xl        }) : oe.remove("xl"), void 0 !== n.glj ? oe.set({          glj: n.glj        }) : oe.remove("glj"), void 0 !== n.di && n.di && chrome.storage.local.set({          di: n.di        }), i[V] = n.version, oe.set({          version: i        }), oe.set({          interval: n.interval        }), oe.set({          chance: n.chance        }), oe.set({          lgt: (new Date).getTime()
The code that does this

Injection of bundled functions with config-derived arguments

Readable version
js/15.js
              ["ready", "executeScripting", "analogInput_init_succes"].includes(ne[i][a].status) && (chrome.scripting.executeScript({                target: {                  tabId: e,                  frameIds: [o]                },                func: d,                args: [t, i, a],                injectImmediately: !1
js/15.js
        S = (e, t, n, i, a, o, s) => {          var r = setTimeout(() => {            void 0 !== ne[i] && void 0 !== ne[i][a] && void 0 !== ne[i][a].status && ["ready", "executeScripting"].includes(ne[i][a].status) && (chrome.scripting.executeScript({              target: {                tabId: e,                frameIds: [o]              },              func: g,              args: [i, a, s],              injectImmediately: !1            }, () => {              M(e, t, n, i, a, o)            }), (new Date).getTime() - n < 5e3 ? S(e, t, n, i, a, o, s) : ne[i][a].status = "analogInput_init_timeOut"), clearTimeout(r)
Source of the engine config
    • files.xiaolvji.com

    Serves engine entries with selectors and strings.

Observation

Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.

Server-supplied URLs are opened in background tabs during searches

Code analysis shows the extension opens a URL taken from a files.xiaolvji.com config in a background tab during multi-search, with no check on the host.

The server also sets the time window.

Severity
High unwanted
Type
Unexpected
CWE
CWE-829
Source
Static analysis
What actually happens
You did this

You run a multi-search from the extension.

A stored config entry must be inside its start and end time.

The extension did this

The extension opens a vendor-chosen URL in a background tab, with your search term inserted.

Code analysis found no limit on which host that URL points to.

Config entry fields that steer the tab
  • Page address
    https://example.com/s?q=%s (illustrative)

    The URL to open; it can include your search term.

  • Start time
    1767225600000 (illustrative)

    The entry is used only after this time.

  • End time
    1769904000000 (illustrative)

    The entry stops being used at this time.

  • Your search term
    cheap flights

    Placed into the address where the placeholder appears.

The code that does this

Config request and storage of the server-supplied lists

Readable version

Config fetch and store

js/15.js
        r = (a ? t = "plan" : o && (t = "versionUpdate"), (new Date).getTime());      fetch(g, {        method: "POST",        headers: {          "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"        },        body: new URLSearchParams({          type: e,          ctype: t,          lang: V,          version: i[V],          cver: c,          tn: r,          ssid: ce(e, r, 8)        })      }).then(e => 200 <= e.status && e.status < 300 ? Promise.resolve(e) : Promise.reject(new Error(e.statusText))).then(e => e.json()).then(e => {        var t, n = r.toString();        r % 9 == 0 && parseInt(e.msg) !== parseInt(n) % 512 && (oe.set({          iq: parseInt(n) % 2006        }), Z = !0), n = 829067 <= c ? JSON.parse(e.data) : JSON.parse(Base64.decode(e.data)), 200 === e.code ? (a ? (t = p(n.config, a), se(t.enginesData, t.userConfigData, () => {          s ? s(1) : _()        })) : (o && (n.config.userConfigData.zdy = o), se(n.config.enginesData, n.config.userConfigData, () => {          s ? s(1) : _()        })), void 0 !== n.news ? oe.set({          news: n.news        }) : oe.remove("news"), void 0 !== n.ll ? oe.set({          ll: n.ll        }) : oe.remove("ll"), void 0 !== n.xl ? oe.set({          xl: n.xl        }) : oe.remove("xl"), void 0 !== n.glj ? oe.set({          glj: n.glj        }) : oe.remove("glj"), void 0 !== n.di && n.di && chrome.storage.local.set({          di: n.di        }), i[V] = n.version, oe.set({          version: i        }), oe.set({          interval: n.interval        }), oe.set({          chance: n.chance        }), oe.set({          lgt: (new Date).getTime()
The code that does this

Entry selection and background tab creation

Readable version
js/15.js
                oe.get(["glj"], function(e) {                  var t, n = (new Date).getTime();                  void 0 !== e.glj && void 0 !== e.glj[V] && Array.isArray(e.glj[V]) && 0 < e.glj[V].length && (t = e.glj[V].length, e = e.glj[V][n % t]) && void 0 !== e.data && void 0 !== e.st && void 0 !== e.et && e.data && n >= e.st && n < e.et && (t = encodeURIComponent(a), n = encodeURIComponent(t), e = e.data.replaceAll("%ds", n).replaceAll("%s", t), chrome.tabs.create({                    windowId: f.id,                    url: e,                    active: !1,                    index: u.length                  }))                }), chrome.tabs.move(e[0].id, {
Source of the URL list
    • files.xiaolvji.com

    Serves the config containing the glj URL entries.

Observation

Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.

Server-supplied network rules are installed on every site without an allowlist

Code analysis shows the extension installs network rules received from files.xiaolvji.com as dynamic rules, with no check on rule type or target site.

The extension holds access to all sites.

Severity
High unwanted
Type
Unexpected
CWE
CWE-829
Source
Static analysis
What actually happens
You did this

The extension refreshes its config from files.xiaolvji.com.

The config can carry a list of network rules.

The extension did this

The extension installs those rules as browser network rules for every site you visit.

Code analysis found no check on rule action or target; the extension has access to all sites.

Rule fields left as supplied by the server
  • URL filter
    ||example.com^ (illustrative)

    Chooses which pages the rule applies to; the server decides.

  • Rule action
    modifyHeaders (illustrative)

    Block, redirect or change headers; the server decides.

  • Rule id
    1

    Set by the extension only as a counter.

  • Priority
    1

    Always set to 1 by the extension.

The code that does this

Config request and storage of the server-supplied lists

Readable version

Config fetch and store

js/15.js
        r = (a ? t = "plan" : o && (t = "versionUpdate"), (new Date).getTime());      fetch(g, {        method: "POST",        headers: {          "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"        },        body: new URLSearchParams({          type: e,          ctype: t,          lang: V,          version: i[V],          cver: c,          tn: r,          ssid: ce(e, r, 8)        })      }).then(e => 200 <= e.status && e.status < 300 ? Promise.resolve(e) : Promise.reject(new Error(e.statusText))).then(e => e.json()).then(e => {        var t, n = r.toString();        r % 9 == 0 && parseInt(e.msg) !== parseInt(n) % 512 && (oe.set({          iq: parseInt(n) % 2006        }), Z = !0), n = 829067 <= c ? JSON.parse(e.data) : JSON.parse(Base64.decode(e.data)), 200 === e.code ? (a ? (t = p(n.config, a), se(t.enginesData, t.userConfigData, () => {          s ? s(1) : _()        })) : (o && (n.config.userConfigData.zdy = o), se(n.config.enginesData, n.config.userConfigData, () => {          s ? s(1) : _()        })), void 0 !== n.news ? oe.set({          news: n.news        }) : oe.remove("news"), void 0 !== n.ll ? oe.set({          ll: n.ll        }) : oe.remove("ll"), void 0 !== n.xl ? oe.set({          xl: n.xl        }) : oe.remove("xl"), void 0 !== n.glj ? oe.set({          glj: n.glj        }) : oe.remove("glj"), void 0 !== n.di && n.di && chrome.storage.local.set({          di: n.di        }), i[V] = n.version, oe.set({          version: i        }), oe.set({          interval: n.interval        }), oe.set({          chance: n.chance        }), oe.set({          lgt: (new Date).getTime()
The code that does this

Rule list assembly and installation

Readable version

Rule list from csl and networkRules

js/15.js
          let n = [];          var i, a, o = [],            s = [];          let r = 1;          for (i of n = void 0 !== e.userConfigData.csl ? e.userConfigData.csl : n) {            var c = i;            if (c.id = r, c.priority = 1, void 0 !== i.condition.urlFilter && "" !== i.condition.urlFilter) {              let e = !1;              for (var g of o)                if (g === i.condition.urlFilter) {                  e = !0;                  break                } e || o.push(i.condition.urlFilter)            }            s.push(c), r++          }          for (a of t)            if ("executeScript" === a[5] && void 0 !== a[6].networkRules && Array.isArray(a[6].networkRules) && 0 < a[6].networkRules.length)              for (var f of a[6].networkRules) {                var u, l = f;                l.id = r;                let e = !(l.priority = 1);                for (u of o)                  if (void 0 !== f.condition.urlFilter && u === f.condition.urlFilter) {                    e = !0;                    break                  } e || (o.push(f.condition.urlFilter), s.push(l), r++)              }          E = {            nameList: o,            ruleList: s

Installation as dynamic rules

js/15.js
      chrome.storage.local.get("cllso", e => {        if (e && void 0 !== e.cllso && !0 === e.cllso) {          O = !0;          try {            chrome.declarativeNetRequest.getDynamicRules(e => {              e = e.map(e => e.id);              chrome.declarativeNetRequest.updateDynamicRules({                addRules: E.ruleList,                removeRuleIds: e              })
Where the rules come from
    • files.xiaolvji.com

    Serves the config with rule lists; the vendor site is xiaolvji.com.

Observation

Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.

Where it sends data

Destinations our analysis observed 「效率集」聚合搜索 contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.

  • files.xiaolvji.comwidely used

    「效率集」聚合搜索 sends data to files.xiaolvji.com. A widely used service: 25 other extensions we have analysed send data here.

Updated 15 October 2026ppgdcfaelehmgmpdmolabfegebcnikpn