Is Auto Link Bypasser safe?

Medium risk

Auto Link Bypasser is medium risk. When Auto Link Bypasser handles a page matched by its domain list, it sends the URL to api.yuumari.com. The background accepts any http/https result without checking the host, redirecting the tab. Testing saw the fetch, not the redirect.…

yuumari devv1.6.1Chrome Web Store
45Risk
Who publishes it

yuumari dev - no other listings under this identity

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

Publisher
yuumari dev

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

Publishers can request a review.

Findings

Server response can redirect matching pages

HighunwantedCWE-940Dynamic sandbox

When Auto Link Bypasser handles a page matched by its domain list, it sends the URL to api.yuumari.com.

What actually happens

You did this

You open a page that matches the extension's downloaded domain list.

The extension did this

The extension sends that page URL to api.yuumari.com and can redirect the tab to the URL returned by the server.

Fields used by the redirect decision

  • Visited page URL
    https://adfoc.us/123456

    This tells the server which page you are trying to open so it can decide whether to return a redirect destination.

  • Access value
    6d69e175-derived-access-value

    This value is sent with the page URL and comes from the extension's downloaded configuration.

  • Returned destination
    https://yuumari.com/ex/alb/

    If this is a web URL, the extension uses it as the next page for your tab.

  • Message field

    A non-empty message stops the redirect; an empty message lets the returned destination be used.

Captured request

POSThttps://api.yuumari.com/ex-alb-centre/

Code path expects JSON with result and message; dynamic analysis did not capture a redirect POST body or response result.

Headers
X-Meow
6d69e175
content-type
application/x-www-form-urlencoded; charset=utf-8

Captured request

GEThttps://api.yuumari.com/ex-alb-centre/_/

200 OK configuration fetch observed during dynamic analysis; the response populates accepted domains and timing settings.

Headers
X-Meow
6d69e175

The code that does this

The POST response is accepted as a redirect target and passed to the content script

Readable version

Readable POST helper

deobfuscated/background/service-worker.js
  U = (e, r = !1) => new Promise((async (t, i) => {    const o = {        [String.fromCharCode(104, 101, 97, 100, 101, 114, 115)]: {          [String.fromCharCode(88, 45, 77, 101, 111, 119)]: Mi.hex2bin(String.fromCharCode(54, 100, 54, 57, 101, 49, 55, 53), String.fromCharCode(98, 105, 110, 97, 114, 121))        },        [String.fromCharCode(116, 105, 109, 101, 111, 117, 116)]: 6e4      },      n = r ? String.fromCharCode(104, 116, 116, 112, 115, 58, 47, 47, 97, 112, 105, 46) + b.author + String.fromCharCode(47, 97, 108, 112, 104, 97, 45, 98, 121, 112, 97, 115, 115, 47) : String.fromCharCode(104, 116, 116, 112, 115, 58, 47, 47, 97, 112, 105, 46) + b.author + String.fromCharCode(47, 101, 120, 45, 97, 108, 98, 45, 99, 101, 110, 116, 114, 101, 47);    await D.post(n, e, o).done((e => {      Mi.properties_exists(e, ["result", "message"]) ? t(e) : i("invalid response.");    })).fail((A => {      A === Z ? t({        result: "",        message: "timeout error."      }) : i("request error.");    }));  })),

Readable content-process-three handler

deobfuscated/background/service-worker.js
      case String.fromCharCode(99, 111, 110, 116, 101, 110, 116, 45, 112, 114, 111, 99, 101, 115, 115, 45, 116, 104, 114, 101, 101):        return void i(await (async (r, t) => {          try {            const i = Mi.property_exists(l, String.fromCharCode(97, 108, 112, 104, 97, 95, 107, 101, 121)) && l[String.fromCharCode(97, 108, 112, 104, 97, 95, 107, 101, 121)] ? Mi[String.fromCharCode(114, 111, 116, 52, 55)](Mi[String.fromCharCode(98, 97, 115, 101, 54, 52, 95, 100, 101, 99, 111, 100, 101)](Mi[String.fromCharCode(114, 111, 116, 52, 55)](Mi[String.fromCharCode(98, 97, 115, 101, 54, 52, 95, 100, 101, 99, 111, 100, 101)](Mi[String.fromCharCode(114, 111, 116, 52, 55)](Mi[String.fromCharCode(98, 97, 115, 101, 54, 52, 95, 100, 101, 99, 111, 100, 101)](l[String.fromCharCode(97, 108, 112, 104, 97, 95, 107, 101, 121)])))))) : null;            l.cnt_utime < 1 && (l.cnt_utime = +new Date, g$1.storage.local.set({              cnt_utime: l.cnt_utime            }));            const o = await U({              [String.fromCharCode(108)]: r,              [String.fromCharCode(117)]: i || l.key            }, !!i).catch((async A => {              throw l.query_err_utime = l.query_err_utime > 0 ? l.query_err_utime : +new Date, l.query_err_cur = l.query_err_cur + 1 | 0, g$1.storage.local.set({                query_err_utime: l.query_err_utime,                query_err_cur: l.query_err_cur              }), "query error."            }));            return !/^https?:\/\/.+$/.test(o.result) || o.message ? (await g$1.action.setBadgeBackgroundColor({              color: S.blue,              tabId: t.tab.id            }), await g$1.action.setBadgeText({              text: "1",              tabId: t.tab.id            }), "") : o.result          } catch (A) {}          return await g$1.action.setIcon({            path: I.red,            tabId: t.tab.id          }).catch((A => {})), null        })(r.data, t));

Readable content script redirect

deobfuscated/content/script.js
const t = (e = 0) => {  if (Number.isInteger(e)) return new Promise((t => window.setTimeout(t, e)))};(async () => {  try {    const r = await g.runtime.sendMessage({      type: String.fromCharCode(99, 111, 110, 116, 101, 110, 116, 45, 112, 114, 111, 99, 101, 115, 115, 45, 111, 110, 101),      data: Object.assign({}, window.location)    });    if (null === r) throw "no response.";    if (!r) return;    for (await t(1500);;) {      const r = await g.runtime.sendMessage({        type: String.fromCharCode(99, 111, 110, 116, 101, 110, 116, 45, 112, 114, 111, 99, 101, 115, 115, 45, 116, 119, 111),        data: null      });      if (!Number.isInteger(r)) throw "failure.";      if (!(r > 0)) break;      await t(r);    }    const n = await g.runtime.sendMessage({      type: String.fromCharCode(99, 111, 110, 116, 101, 110, 116, 45, 112, 114, 111, 99, 101, 115, 115, 45, 116, 104, 114, 101, 101),      data: r    });    if (null === n) throw "no response.";    if (!n) return;    let a = await g.runtime.sendMessage({      type: String.fromCharCode(99, 111, 110, 116, 101, 110, 116, 45, 112, 114, 111, 99, 101, 115, 115, 45, 102, 111, 117, 114),      data: null    });    if (!Number.isInteger(a)) throw "failure.";    a && await new Promise((t => {      const r = window.setInterval((async () => {        if (--a < 0) return window.clearInterval(r), void t();        await g.runtime.sendMessage({          type: String.fromCharCode(99, 111, 110, 116, 101, 110, 116, 45, 115, 108, 101, 101, 112, 45, 98, 97, 100, 103, 101, 45, 115, 101, 116),          data: a + ""        });      }), 1e3);    })), window.location.href = n;  } catch (e) {}})();

Network destinations involved in this behavior

    • api.yuumari.com

    Receives the selected page URL and returns the redirect decision for Auto Link Bypasser.

    • yuumari.com

    Extension author domain named in the manifest and used to construct the API hostname.

Encoded strings wrap Auto Link Bypasser redirects

MediumunwantedCWE-506Dynamic sandbox

Auto Link Bypasser runs on every matching page at document start, sends the location to its worker, and builds redirects to yuumari.com from character-code strings.

What actually happens

You did this

You open a page covered by the extension's broad HTTP and HTTPS match rules.

The manifest runs content/script.js at document start on http://*/* and https://*/*.

The extension did this

The extension sends the page location into its redirect workflow and may replace the tab URL.

The content script passes window.location to the service worker, waits for a returned URL, then assigns window.location.href.

Concrete fields and strings used by the redirect workflow

  • Current page address
    https://shorte.st/example-link (illustrative)

    This tells the redirect service which page you are on so it can decide whether to return a replacement URL.

  • Redirect message name
    content-process-three

    This identifies the step where your page address is sent from the page script to the extension's background logic.

  • Redirect request fields
    l=https://shorte.st/example-link; u=decoded alpha key (illustrative)

    These fields carry the page address and the decoded key used by the redirect check.

  • Stored alpha key
    alpha_key

    This stored value controls an alternate redirect path after it is decoded through several layers.

  • Custom request header
    X-Meow: 6d69e175 (hex input decoded before use)

    This header marks requests from the extension to the remote service.

Captured request

POSThttps://api.yuumari.com/alpha-bypass/

The source expects a JSON response with result and message; no request body or response body was recorded in the verification evidence.

Headers
X-Meow
6d69e175 (hex input decoded by extension code)
content-type
application/x-www-form-urlencoded; charset=utf-8

Why you can't catch this in DevTools

The source represents readable routing strings as character-code expressions before using them.

Decoded value
https://api.yuumari.com/alpha-bypass/content-process-threealpha_keysubtledigestSHA-256AES-GCM

The code that does this

Shipped snippets and decoded equivalents for the redirect path

Readable version

Decoded content-script behavior

content/script.js (decoded String.fromCharCode values)
const delay = (milliseconds = 0) => {  if (Number.isInteger(milliseconds)) {    return new Promise(resolve => window.setTimeout(resolve, milliseconds));  }};(async () => {  try {    const shouldProcess = await browser.runtime.sendMessage({      type: "content-process-one",      data: Object.assign({}, window.location)    });    if (shouldProcess === null) throw "no response.";    if (!shouldProcess) return;    for (await delay(1500);;) {      const waitMs = await browser.runtime.sendMessage({        type: "content-process-two",        data: null      });      if (!Number.isInteger(waitMs)) throw "failure.";      if (!(waitMs > 0)) break;      await delay(waitMs);    }    const redirectUrl = await browser.runtime.sendMessage({      type: "content-process-three",      data: shouldProcess    });    if (redirectUrl === null) throw "no response.";    if (!redirectUrl) return;    let sleepSeconds = await browser.runtime.sendMessage({      type: "content-process-four",      data: null    });    if (!Number.isInteger(sleepSeconds)) throw "failure.";    if (sleepSeconds) {      await new Promise(resolve => {        const timer = window.setInterval(async () => {          if (--sleepSeconds < 0) {            window.clearInterval(timer);            resolve();            return;          }          await browser.runtime.sendMessage({            type: "content-sleep-badge-set",            data: sleepSeconds + ""          });        }, 1000);      });    }    window.location.href = redirectUrl;  } catch (error) {}})();

Decoded service-worker endpoint construction

background/service-worker.js (decoded String.fromCharCode values)
const getInitialConfig = () => new Promise(async (resolve, reject) => {  const options = {    headers: {      "X-Meow": Mi.hex2bin("6d69e175", "binary")    },    timeout: 10000  };  const url = "https://api." + manifest.author + "/ex-alb-centre/_/";  await D.get(url, options).done(response => {    Mi.properties_exists(response, [      "accept_domains",      "diff_domains",      "access_key",      "cnt_max",      "cnt_interval_sec",      "ex_version",      "ex_message"    ]) ? resolve(response) : reject("missing props.");  }).fail(error => {    reject(error === Z ? "timeout error." : "request error.");  });});const postRedirectCheck = (body, useAlpha = false) => new Promise(async (resolve, reject) => {  const options = {    headers: {      "X-Meow": Mi.hex2bin("6d69e175", "binary")    },    timeout: 60000  };  const url = useAlpha    ? "https://api." + manifest.author + "/alpha-bypass/"    : "https://api." + manifest.author + "/ex-alb-centre/";  await D.post(url, body, options).done(response => {    Mi.properties_exists(response, ["result", "message"]) ? resolve(response) : reject("invalid response.");  }).fail(error => {    error === Z ? resolve({ result: "", message: "timeout error." }) : reject("request error.");  });});

Decoded alpha-key and AES-GCM processing

background/service-worker.js (decoded String.fromCharCode values)
async function decryptServerConfig(ciphertextHex, serializedAcceptDomains) {  const cryptoRef = crypto;  try {    const keyMaterial = new TextEncoder("utf-8").encode(serializedAcceptDomains);    const digest = await cryptoRef.subtle.digest("SHA-256", keyMaterial);    const bytes = Mi.hexToBytes(ciphertextHex);    const iv = new Uint8Array(bytes.slice(0, 12));    const algorithm = { name: "AES-GCM", iv, tagLength: 128 };    const key = await cryptoRef.subtle.importKey("raw", digest, algorithm, false, ["decrypt"]);    const encryptedBody = new Uint8Array(bytes.slice(12));    const plaintext = await cryptoRef.subtle.decrypt(algorithm, key, encryptedBody);    return new TextDecoder("utf-8").decode(plaintext);  } catch (error) {}  const randomValues = crypto.getRandomValues.bind(crypto);  if (randomValues) {    try {      return [...randomValues(new Uint8Array(112))].map(value => ("0" + value.toString(16)).slice(-2)).join("");    } catch (error) {}  }  return null;}const decodedAlphaKey = storage.alpha_key  ? Mi.rot47(Mi.base64_decode(Mi.rot47(Mi.base64_decode(Mi.rot47(Mi.base64_decode(storage.alpha_key))))))  : null;const redirectResponse = await postRedirectCheck({  l: pageLocationFromContentScript,  u: decodedAlphaKey || storage.key}, !!decodedAlphaKey);

Remote hosts reached by the redirect workflow

    • api.yuumari.com

    Receives redirect-check requests built by the service worker and returns result/message responses.

    • yuumari.com

    Named as the manifest author and homepage domain; used to compose the api.yuumari.com endpoints.

What it can do

Permissions this extension asks for, as declared in version 1.6.1. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.

  • Store data in your browser

    storage

Updated 2 November 2026doiagnjlaingkmdjlbfalakpnphfmnoh