Is UnTrap for YouTube — Block Shorts, Remove Recommendations, Detox & Focus safe?

Medium risk

UnTrap is medium risk. Using transcript summarization on a YouTube watch page builds a request with the video URL, a stored user ID, language, date, and initial-request flag, posted to untrap.app. Traced from shipped code; an earlier run captured no live body.

yevhen.tretiakovv12.1Chrome Web Store
45Risk
Who publishes it

yevhen.tretiakov - 1 other listing from the same operator, none carrying a finding

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

Publisher
yevhen.tretiakov

Same store account

1 other listing published from this account, 70k+ users between them, none of them carrying a finding.

Shared hosts - 1 hostname

Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.

untrap.app
Also called by 4 other listings, including UnTrap for YouTube

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

YouTube video URL sent for transcription summaries

Using transcript summarization on a YouTube watch page builds a request with the video URL, a stored user ID, language, date, and initial-request flag, posted to untrap.app.

Traced from shipped code; an earlier run captured no live body.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You ask the extension to summarize a YouTube video's transcript.

The request path runs when the transcript tab is selected or the summary panel generates transcript content.

The extension did this

The extension prepares a JSON request with the current video URL and your stored identifier.

The request is addressed to untrap.app's transcription summarization API.

02EvidenceFIELD TABLE
Fields constructed for the transcription request
FieldValueWhy it matters
Current YouTube video
https://www.youtube.com/watch?v=dQw4w9WgXcQ (illustrative)Shows which video you asked the service to summarize.
Stored user identifier
b6f2d8c1-3a10-4e1f-90d6-5b2c6b7e2a41 (illustrative)Lets the service associate the summary request with the same extension user record across requests.
Summary language
EnglishTells the service which language to use for the transcript summary.
Request date
2026-07-14 (illustrative)Adds the day when the summary request was made.
Initial request flag
trueIndicates whether this is the first transcript summary request for the current video view.
03EvidenceNETWORK CAPTURE
Captured request
POSThttps://untrap.app/api/summarize/transcription
The source parses a JSON response and renders returned transcript chunks into the summary panel.
Headers
Content-Typeapplication/json
04EvidenceCODE COMPARE
The code that does this

The transcript summary request body and POST sender

What it actually does
Initial transcript summary requestcontent/js/VideoSummarize/summarize-functionality/transcription-summary.js
function generateTranslateVideoSummary(tabItem) {
  storageService
    .get([getConstNotSyncing.notSyncingState, getConst.system])
    .then(async (result) => {
      const notSyncingState = result[getConstNotSyncing.notSyncingState] ?? {};
      const systemState = result[getConst.system] ?? {};
      const sharedState = systemState[getConst.sharedState] ?? {};
      const summarizeWindowState =
        systemState[getConst.summarizeWindowState] ?? {};

      const languageToTranslate =
        summarizeWindowState[getConst.transcriptTranslateLanguage] ?? "English";
      const userEmail =
        notSyncingState[getConstNotSyncing.pro_usernameData] ?? "";

      const userIdentifier = sharedState[getConst.userUniqueIdentifier] ?? "";

      const currentDate = getRequestDate();

      const currentHref = window.location.href;
      const videoSummarizeWindowContainer = document.getElementById(
        "videoSummarizeWindowContainer",
      );

      if (videoSummarizeWindowContainer) {
        const videoSummarizeContainer =
          videoSummarizeWindowContainer.querySelector("#contentContainer");

        transcriptionAbortController = new AbortController();

        try {
          const translate = await summarizeService.summarizeRequest({
            body: {
              url: currentHref,
              language: languageToTranslate,
              user_identifier: userIdentifier,
              request_date: currentDate,
              is_initial: true,
            },
            controller: transcriptionAbortController,
            fetchUrl: _ENDPOINTS.summarize.translate,
          });

          if (videoSummarizeContainer) {
            copiedSummaryText.transcripts += "";

            copiedSummaryText.transcripts += `${getVideoName()}\n\n`;

            if (tabItem && tabItem.hasAttribute("select")) {
              videoSummarizeContainer.innerHTML = "";

              const parsedTranscriptionHtml = parseAndGenerateTranscriptionHTML(
                translate.translated_chunk,
                translate.chunk_limit_exceed,
                false,
              );

              const purifyParsedTranscriptionHtml = DOMPurify.sanitize(
                parsedTranscriptionHtml,
              );

              videoSummarizeContainer.innerHTML = purifyParsedTranscriptionHtml;
            }

            htmlContentState.transcripts = parseAndGenerateTranscriptionHTML(
              translate.translated_chunk,
              translate.chunk_limit_exceed,
              true,
            );

            copyButtonDisabledHandler();

            transcriptionAbortController = undefined;
            loadMoreTranslate(videoSummarizeContainer, currentHref);
          }
        } catch (error) {
          transcriptionAbortController = undefined;
          if (error.message !== "signal is aborted without reason") {
            if (videoSummarizeContainer) {
              if (tabItem && tabItem.hasAttribute("select"))
                if (error.message === `You’ve reached the daily limit`) {
                  videoSummarizeContainer.innerHTML = getFreeQuotaReachedHtml(
                    userEmail,
                    userIdentifier,
                  );
                } else if (
                  error.message ===
                  "You have reached your free request limit. To continue using the summarize feature, please upgrade to Plus plan"
                ) {
                  videoSummarizeContainer.innerHTML = getFreeQuotaReachedHtml(
                    userEmail,
                    userIdentifier,
                    error.message,
                  );
                } else if (error.message === "Transcript not found") {
                  getCustomErrorHtml(videoSummarizeContainer, error.message);
                } else if (error.message === "Too many requests") {
                  getCustomErrorHtml(
                    videoSummarizeContainer,
                    "Too many requests. Please try again later",
                    () => generateTranslateVideoSummary(tabItem),
                  );
                } else {
                  getCustomErrorHtml(
                    videoSummarizeContainer,
                    "Something went wrong.",
                    () => generateTranslateVideoSummary(tabItem),
                  );
                }
            }
          }
        }
      }
    });
}
JSON POST helpercontent/js/VideoSummarize/summarize-utils.js
async function summarizeFetchFunction(
  body,
  controller,
  fetchUrl,
  timeoutMs = 60_000,
) {
  const id = setTimeout(() => controller.abort(), timeoutMs);

  try {
    const response = await fetch(fetchUrl, {
      method: "POST",
      signal: controller.signal,
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
    });

    if (!response.ok) {
      const errorText = await response.json();
      throw new Error(`${errorText.error}`);
    }

    const data = await response.json();
    return data;
  } catch (err) {
    if (err.name === "AbortError") {
      throw new Error("Request timed out");
    }
    throw err;
  } finally {
    clearTimeout(id);
  }
}
Endpoint mappingcontent/server/serverMethod.js
const _ENDPOINTS = {
  auth: {
    login: "https://untrap.app/db/untrap/login.php",
    signup: "https://untrap.app/db/untrap/signup.php",
    updatePassword: "https://untrap.app/db/untrap/updatePass.php",
    sendVerificationCode:
      "https://untrap.app/api/untrap/send_verification_code",
    verifyCode: "https://untrap.app/api/untrap/verify_code",
    forgotPassword: "https://untrap.app/api/untrap/forgot-password",
    deleteUser: "https://untrap.app/api/untrap/delete_user",
    getUser: "https://untrap.app/api/untrap/get_user",
  },
  sync: {
    updateFields: "https://untrap.app/db/untrap/updateFields.php",
    fetchFields: "https://untrap.app/db/untrap/fetchFields.php",
  },
  settings: {
    getAll: "https://untrap.app/api/untrap/get_settings",
    getPartial: "https://untrap.app/api/untrap/get_partial_settings",
  },
  summarize: {
    checkLimit: "https://untrap.app/api/check_request_limit",
    insight: "https://untrap.app/api/summarize/insight",
    timestamp: "https://untrap.app/api/summarize/timestamp",
    comments: "https://untrap.app/api/summarize/comments",
    translate: "https://untrap.app/api/summarize/transcription",
  },
};
05EvidenceTHIRD PARTY LIST
Destination for transcript summarization
  • untrap.app

    Receives the transcript summarization POST containing the current YouTube URL and request metadata.

Updated 30 September 2026enboaomnljigfhfjfoalacienlhjlfil