Is Manuals Search safe?

Medium risk

ManualsSearch is medium risk. Manuals Search stores GUID e1d0dc83-340b-60c6-1a09-8d9dc1f59eaf in Chrome sync storage, adds it plus type tag Y243_F1_221843_071226 to searches sent through search.freshysearch-api.net via a redirect rule, and to omnibox manual-search URLs.

manualssearchv1.23.130Chrome Web Store
45Risk
Who publishes it

Tightrope Interactive - 14 other listings from the same operator, 3 of them carrying a finding

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

Publisher
manualssearch
Declared legal entity
Tightrope Interactive
Registered address
248 3rd Street, Oakland, CA 94607, US

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

Publishers can request a review.

Findings

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

Persistent GUID tags Manuals Search queries

Manuals Search stores GUID e1d0dc83-340b-60c6-1a09-8d9dc1f59eaf in Chrome sync storage, adds it plus type tag Y243_F1_221843_071226 to searches sent through search.freshysearch-api.net via a redirect rule, and to omnibox manual-search URLs.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You install Manuals Search and use its search provider or manual-search keyword.

The extension did this

The extension adds the same install GUID and tracking tag to search URLs sent through Freshy Search.

Dynamic analysis observed the GUID in Chrome sync storage and in a redirect rule for search.freshysearch-api.net.

02EvidenceSTORAGE DUMP
What's stored on your device

This stores the install identifier in browser-synced storage, so later searches can be tied back to the same extension install.

Locationchrome.storage.sync key 'guid'
Contents (JSON)
{
  "guid": "e1d0dc83-340b-60c6-1a09-8d9dc1f59eaf"
}
03EvidenceNETWORK CAPTURE
Captured request
GEThttps://search.freshysearch-api.net/crx/search.php?k=manual&type=Y243_F1_221843_071226&guid=e1d0dc83-340b-60c6-1a09-8d9dc1f59eaf
Redirect target URL produced by the observed Chrome dynamic redirect rule; no request body was recorded.
04EvidenceFIELD TABLE
Concrete values attached to search requests
FieldValueWhy it matters
Install GUID
e1d0dc83-340b-60c6-1a09-8d9dc1f59eafThis value lets repeated searches be associated with the same extension install.
Tracking tag
Y243_F1_221843_071226This adds partner and install-attribution context to each tagged search URL.
Search term
manualThis reveals the search text that was routed through the extension's search provider.
Tagged search URL
https://search.freshysearch-api.net/crx/search.php?k=manual&type=Y243_F1_221843_071226&guid=e1d0dc83-340b-60c6-1a09-8d9dc1f59eafThis combines the search term with the persistent identifier in one request URL.
05EvidenceCODE COMPARE
The code that does this

Source paths that request, store, and reuse the GUID

What it actually does
Install API call stores guid in Chrome sync storagelib/ext.js
const install = async () => {
    const src =
        `https://api.${this.config.apiDomain}/api/v2/json/install?` +
        `&eType=${this.config.eType}&ext.yid=${
            this.config.yID
        }&ext.domain=${await getSetting(
            "domain"
        )}&ext.partner_name=${await getSetting(
            "partner_name"
        )}&ext.region=${await getSetting(
            "region"
        )}&ext.id=${await getSetting(
            "extId"
        )}&ext.version=${await getSetting("extVersion")}`;

    const installRes = await fetch(src, {
        headers: {
            "Content-Type": "application/json",
        },
    });
    if (!installRes.ok) {
        console.error("Error with install req");
        return;
    }
    const config = await installRes.json();
    await Promise.all(
        Object.entries(config).map(
            async ([key, value]) =>
                await setSetting(key, value, key === "guid")
        )
    );
};
Type tag compositionlib/ext.js
const setTypeTag = async () => {
    const y = this.config.yID;
    const f = (await getSetting("subid")) || 1;
    const t = (await getSetting("tbid")) || 11745;
    const d = (await getSetting("installDate")) || null;
    if (y && f && t)
        await setSetting("type", `Y${y}_F${f}_${t}${d ? `_${d}` : ""}`);
};
Dynamic redirect rules include type and guidlib/ext.js
const installHandler = async details => {
    if (details && details.reason && details.reason === "install") {
        await getConfigCookie();
        // first run of extension
        if (!(await getSetting("guid", true))) {
            const extInfo = await chrome.management.getSelf();
            await setSetting("extId", extInfo.id);
            await setSetting("extVersion", extInfo.version);
            const now = new Date();
            const installDate = `${`0${now.getMonth() + 1}`.slice(
                -2
            )}${`0${now.getDate()}`.slice(-2)}${now
                .getFullYear()
                .toString()
                .slice(-2)}`;
            await setSetting("installDate", installDate);
            await install();
            await setTypeTag();
            const guid = await getSetting("guid", true);
            const type = await getSetting("type");
            chrome.declarativeNetRequest.updateDynamicRules({
                removeRuleIds: [1, 2],
                addRules: [
                    {
                        id: 1,
                        priority: 1,
                        action: {
                            type: "redirect",
                            redirect: {
                                regexSubstitution: `https://search.${this.config.apiDomain}/crx/search.php?k=\\1&type=${type}&guid=${guid}`,
                            },
                        },
                        condition: {
                            regexFilter: `https://search.${this.config.apiDomain}/search/(.*)`,
                            isUrlFilterCaseSensitive: false,
                            resourceTypes: ["main_frame"],
                        },
                    },
                    {
                        id: 2,
                        priority: 2,
                        action: {
                            type: "redirect",
                            redirect: {
                                regexSubstitution: `https://${this.config.homepage}/manuals?q=\\2&type=${type}&guid=${guid}`,
                            },
                        },
                        condition: {
                            regexFilter: `https://search.${this.config.apiDomain}/search/(.+)?q=(.+)`,
                            isUrlFilterCaseSensitive: false,
                            resourceTypes: ["main_frame"],
                        },
                    },
                ],
            });
            updateCWSAndLPTab();
            if (await getSetting(TY_COOKIE_NAME)) {
                openUrl(
                    decodeURIComponent(await getSetting(TY_COOKIE_NAME)),
                    false
                );
            }
            startupHandler();
        }
    } else {
        setSetting("firstNT", true, true);
    }
};
Omnibox search appends the same valueslib/omnibox.js
const onInputEntered = async (text, OnInputEnteredDisposition) => {
    const guid = await this.ext.getSetting("guid", true);
    const type = await this.ext.getSetting("type");
    const url = new URL(
        `https://search.freshy.com/manuals?q=${encodeURIComponent(text)}&type=${type}&guid=${guid}`
    );
    url.searchParams.set("guid", guid);
    url.searchParams.set("type", type);
    if (OnInputEnteredDisposition === "currentTab") {
        chrome.tabs.create({ url: url.toString() });
    } else {
        chrome.tabs.update({ url: url.toString() });
    }
};
06EvidenceTHIRD PARTY LIST
Freshy Search hosts involved in the flow
  • api.freshysearch-api.net

    Receives the install request and returns configuration values including the persistent GUID.

  • search.freshysearch-api.net

    Receives redirected search URLs with the GUID and type tag attached.

  • search.freshy.com

    Receives omnibox manual-search URLs with the same GUID and type tag attached.

What it can do

Permissions this extension asks for, as declared in version 1.23.130. 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 freshysearch-api.net

    *://*.freshysearch-api.net/*

  • Read and change your data on search.freshy.com

    *://*.search.freshy.com/core/v2/complete/*

  • Read and change cookies, including the ones that keep you signed in

    cookies

  • Store data in your browser

    storage

  • See the address and title of every tab you have open

    tabs

  • Block and redirect the requests your browser makes

    declarativeNetRequest

Updated 30 September 2026mefdlpflnlcgildomebjfhmdhflimfnm