Is Summary Webpage - Summarize Youtube videos | AI - Assistant safe?

High risk

Summary Webpage extracts the full article text of the active page and sends it to Hugging Face AI servers using hardcoded API tokens.

When you click the toolbar button on any page, the extension reads the full readable article text via Mozilla Readability and forwards up to 14,000 characters to Hugging Face's inference router (cerebras provider, Qwen3-32B model) to generate a summary. Although the UI is labelled 'Summary with ChatGPT' and offers an OpenAI login, the active summarisation path always routes page content to Hugging Face and ignores any OpenAI key you enter. The requests are authenticated with one of 13 Hugging Face API tokens embedded in the shipped code, which rotate when rate-limited.

ChatGPT Summaryv1.0.8Chrome Web Store
75Risk

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

Publishers can request a review.

Findings

Page content sent to HuggingFace for summaries

Summarizing a page sends its readable text to HuggingFace's router for a Cerebras chat completion.

The worker embeds HuggingFace tokens, adds the stored/default prompt, truncates text past 14,000 characters, sends it to Qwen/Qwen3-32B.

Severity
High unwanted
Type
Unexpected
CWE
CWE-522
Source
Dynamic sandbox
What actually happens
You did this

You ask the extension to summarize the page you are reading.

The extension did this

The extension forwards the page text to an external AI inference service.

Fields placed into the AI completion request
  • Page text
    Summarise the following article in bullet points: The city council approved a new transit budget after a three-hour meeting. (illustrative page text)

    Text from the page you chose to summarize: article text, transcript text, internal pages, or other readable content on that page.

  • Summary prompt
    Summarise the following article in bullet points:

    The instruction that shapes the answer is sent with the page text.

  • Embedded API token
    hf_<redacted>

    The request uses a token bundled inside the extension rather than a token you provide.

  • Model selection
    Qwen/Qwen3-32B via provider cerebras

    The request names the external AI model that receives the prompt.

Captured request
POSThttps://router.huggingface.co/cerebras/v1/chat/completions
Headers
Content-Type
application/json
Authorization
Bearer hf_<redacted>
The code that does this

The shipped worker sends page text through HuggingFace chat completion

Readable version

Readable content-script equivalent

deobfuscated/javascripts/script.js
function summarizeReadableText(readableText) {    let finalSummary;    const port = chrome.runtime.connect();    port.onMessage.addListener((message) => {        if (message.event === "DONE") {            stopLoading();            showSummaryHeader();            showFooter();            document.getElementById("readergpt__shadowRoot").shadowRoot.getElementById("copyBtn").addEventListener("click", () => {                navigator.clipboard.writeText(finalSummary);            });            return;        }        if (message.text) {            showSummaryText(message.text);            finalSummary = message.text;            return;        }        if (message.error) {            stopLoading();            showError(message.error);        }    });    hideLoginAndHeader();    showLoadingState();    port.postMessage({        pageContent: readableText    });}if (readabilityResult && readabilityResult.textContent) {    summarizeReadableText(readabilityResult.textContent);} else {    showWarning("No readable text found on the page.");}

Readable worker equivalent

deobfuscated/javascripts/worker.js
chrome.runtime.onConnect.addListener((port) => {    port.onMessage.addListener(async (message) => {        const promptAndPageText = await buildPrompt(message.pageContent);        try {            let accumulatedText = "";            for await (const chunk of summarizeWithHuggingFace(promptAndPageText)) {                accumulatedText += chunk;                await port.postMessage({                    text: accumulatedText,                    messageId: crypto.randomUUID(),                    conversationId: crypto.randomUUID()                });            }            await port.postMessage({                event: "DONE"            });        } catch (error) {            port.postMessage({                error: error.message            });        }    });});async function buildPrompt(pageContent) {    if (pageContent.length > 14000) {        pageContent = pageContent.slice(0, 14000);    }    const prompt = await chrome.storage.local.get("summary_prompt").then((stored) => {        return stored && stored.summary_prompt ? stored.summary_prompt : "Summarise the following article in bullet points:";    });    return `${prompt} ${pageContent}`;}

Readable HuggingFace completion equivalent

deobfuscated/javascripts/worker.js
const HUGGINGFACE_TOKENS = [    "hf_<redacted>",    "hf_<redacted>",    "hf_<redacted>",    "hf_<redacted>",    "hf_<redacted>",    "hf_<redacted>",    "hf_<redacted>",    "hf_<redacted>",    "hf_<redacted>",    "hf_<redacted>",    "hf_<redacted>",    "hf_<redacted>",    "hf_<redacted>"];async function* summarizeWithHuggingFace(promptAndPageText, triedTokens = []) {    const availableTokens = HUGGINGFACE_TOKENS.filter((token) => !triedTokens.includes(token));    if (!availableTokens.length) {        throw new Error("Rate limit reached. You reached free usage limit");    }    const token = availableTokens[Math.floor(Math.random() * availableTokens.length)];    try {        const client = new InferenceClient(token);        const response = await client.chatCompletion({            provider: "cerebras",            model: "Qwen/Qwen3-32B",            messages: [                {                    role: "user",                    content: promptAndPageText                }            ]        });        if (response && response.choices[0]) {            yield response.choices[0].message.content.replace(/<think>[\s\S]*<\/think>/g, "").slice(1, -1).slice(1, -1);        }    } catch (error) {        yield* summarizeWithHuggingFace(promptAndPageText, triedTokens.concat(token));    }}
External service contacted by the summary path
    • router.huggingface.co

    Receives the POST request from the bundled HuggingFace client and routes it to the selected inference provider.

Page text is sent to AI services for summaries

Clicking summarize sends the page's text from the content script to the service worker, which prepends the summary prompt, keeps up to 14,000 characters, forwards it to an AI endpoint.

A traffic run never triggered this; no body captured.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-200
Source
Dynamic sandbox
What actually happens
You did this

You click the extension's summary action on a web page.

The extension did this

The extension extracts the page's readable text and sends it to an external AI service for summarization.

Data included in the summary request
  • Page text
    The tower is 324 metres tall and was the tallest structure in Paris (illustrative)

    This is the readable copy from the page you are viewing, including article text, headings, and other visible page content.

  • Summary prompt
    Summarise the following article in bullet points:

    This tells the AI service what to do with the page text you requested to summarize.

  • Character limit
    14000

    The extension can send a substantial portion of the page in one request rather than just the title or URL.

Captured request
POSThttps://router.huggingface.co/cerebras/v1/chat/completions

The HuggingFace inference client returns a chat completion; the extension streams the returned text back into the page overlay.

Headers
Content-Type
application/json
Authorization
Bearer <redacted>
The code that does this

The content script extracts page text and sends it to the service worker

Readable version

Same shipped content script after deobfuscation

javascripts/script.js
var e = i(107);i.n(e);let t = "readergpt__shadowRoot";var a = new e.Readability(document.cloneNode(!0)).parse();a && a.textContent ? function(e) {    let t, i = chrome.runtime.connect();    i.onMessage.addListener((e => {        if (e.text) {            t = e.text;        }    }));    i.postMessage({        pageContent: e    });}(a.textContent) : r("No readable text found on the page.");
The code that does this

The service worker builds the AI prompt and calls HuggingFace/Cerebras

Readable version

Request construction in the bundled HuggingFace client

javascripts/worker.js
function En(e, t, n, a, i) {    const {accessToken: o, endpointUrl: r, provider: s, model: l, ...c} = n, p = t.provider, {includeCredentials: d, task: u, signal: m, billTo: f} = i ?? {}, h = (() => {        if (t.clientSideRoutingOnly) {            if (o && o.startsWith("hf_")) throw new Error(`Provider ${p} is closed-source and does not support HF tokens.`);            return "provider-key";        }        return o ? o.startsWith("hf_") ? "hf-token" : "provider-key" : "include" === d ? "credentials-include" : "none";    })(), g = r ?? e, y = t.makeUrl({        authMethod: h,        model: g,        task: u    }), b = t.prepareHeaders({        accessToken: o,        authMethod: h    }, "data" in n && !!n.data);    f && (b["X-HF-Bill-To"] = f);    const w = [ "@huggingface/inference/3.13.1", "undefined" != typeof navigator ? navigator.userAgent : void 0 ].filter((e => void 0 !== e)).join(" " );    b["User-Agent"] = w;    const v = t.makeBody({        args: c,        model: e,        task: u,        mapping: a    });    let x;    return "string" == typeof d ? x = d : !0 === d && (x = "include"), {        url: y,        info: {            headers: b,            method: "POST",            body: v,            ...x ? {                credentials: x            } : void 0,            signal: m        }    };}
External services reached by the summary flow
    • router.huggingface.co

    Receives the chat-completion request routed to the Cerebras provider for page summarization.

    • chat.openai.com

    Used by the extension for ChatGPT session access and feedback requests when the ChatGPT login path is used.

Where it sends data

Destinations our analysis observed Summary Webpage 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.

  • router.huggingface.co

    Summary Webpage sends data to router.huggingface.co. No other extension we have analysed sends data here.

Updated 30 September 2026mikcekmbahpbehdpakenaknkkedeonhf