Is Xiaohongshu for Desktop safe?

Medium risk

Xiaohongshu for Desktop sends each post's ID and Xiaohongshu access token to a third-party server (api.old-panda.com) to fetch media.

When you download a Xiaohongshu post, the extension reads the post ID and the post's xsec_token (Xiaohongshu's own per-resource signed access token) from the page URL and forwards both to api.old-panda.com, which returns the post's image and video URLs, title and text. Separately, its translate buttons send the visible text of a post or a selected comment to Google Translate's public endpoint. Both happen only when you click download or translate, not in the background.

Seiriv1.2.9Chrome Web Store
45Risk

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

Publishers can request a review.

Findings

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-200
SourceAI SANDBOX

Download action sends Xiaohongshu token to old-panda API

Clicking the download button makes the content script read the post ID and xsec_token from the page URL and send them to the worker, which GETs api.old-panda.com for the media, title, and text.

A browsing-only run didn't trigger this.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You click the download button that the extension adds to a Xiaohongshu or Rednote post.

The extension did this

The extension reads the post ID and page token from the URL and sends them to api.old-panda.com.

02EvidenceFIELD TABLE
Values forwarded for the download lookup
FieldValueWhy it matters
Post identifier
65f1a2b3c4d5e6f7890abcdeThis identifies the exact Xiaohongshu or Rednote post you chose to download.
Post access token
AT_eyJzaWQiOiJ4aHMiLCJub25jZSI6IjE3MTYyNjM0MDAifQThis token is copied from the page URL and travels with the post lookup request.
Returned media URLs
https://sns-img-qc.xhscdn.com/1040g00830vtb9apg6g005n4bq6c0j6a2tq8h6f8The response can describe the images or videos that will be saved from that post.
Returned title and text
Weekend route notes Coffee shops and photo locations near the riverThe response can include the title and written content of the post you selected.
03EvidenceNETWORK CAPTURE
Captured request
GEThttps://api.old-panda.com/image/xiaohongshu/?post_id=65f1a2b3c4d5e6f7890abcde&xsec_token=AT_eyJzaWQiOiJ4aHMiLCJub25jZSI6IjE3MTYyNjM0MDAifQ
The service worker expects 200 OK JSON and forwards the parsed response to the content script.
Headers
Content-Typeapplication/json
04EvidenceCODE COMPARE
The code that does this

The shipped code parses the token and forwards it to the API

What it actually does
Readable equivalent of the content-script parserassets/js/content.js
  async downloadPostByHref(href) {
    if (!href.includes(XHS_DOMAIN_ZH) && !href.includes(XHS_DOMAIN_EN)) {
      throw new Error("Unsupported post URL.");
    }

    const url = new URL(href);
    const postId = url.pathname
      .split("/")
      .filter((e) => e)
      .pop();
    const xsecToken = url.searchParams.get("xsec_token") || "";

    const response = await browser.runtime.sendMessage({
      action: ACTION_GET_DL_DATA,
      postId,
      xsecToken,
    });

    if (!response?.success) {
      throw new Error(
        getErrorMessage(response?.message, "Failed to fetch post data."),
      );
    }

    const storageData = await getStorage([STORAGE_FILENAME_FORMAT]);
    const fileNameFormat = storageData[STORAGE_FILENAME_FORMAT];
    const { baseName, zipBlob } = await zipFile(
      response.data,
      postId,
      fileNameFormat,
    );
    const fileName = `${baseName}${ZIP_FILE_NAME_SUFFIX}`;
    this.saveBlob(zipBlob, fileName);
    return fileName;
  }
Readable equivalent of the service-worker request handlerassets/js/background.js
  async handleMessage(message, sendResponse, Filter) {
    if (message.action === ACTION_GET_DL_DATA) {
      try {
        const response = await fetch(
          `${DL_API_URL}${message.postId}&xsec_token=${message.xsecToken}`,
          {
            headers: { "Content-Type": "application/json" },
          },
        );

        if (response.status == 200) {
          const data = await response.json();
          sendResponse({ success: true, data });
        } else {
          throw new Error(
            "Failed to get video information. Please try again later or check your network connection.",
          );
        }
      } catch (error) {
        sendResponse({ success: false, message: error.message });
      }
    } else if (message.action === ACTION_GET_TRANSLATE_DATA) {
      const currentLang = await getStorage([STORAGE_TRANSLATE_LANGUAGE]);
      let lang =
        currentLang[STORAGE_TRANSLATE_LANGUAGE] || DEFAULT_TRANSLATE_LANG;
      if (lang === DEFAULT_TRANSLATE_LANG) {
        lang = browser.i18n.getUILanguage();
      }
      try {
        const data = await this.translateText(
          message.text,
          message.tagText,
          lang,
        );
        sendResponse({ success: true, data });
      } catch (error) {
        sendResponse({ success: false, message: error.message });
      }
    } else if (message.action === ACTION_OPEN_SETTING) {
      await browser.tabs.create({
        url: browser.runtime.getURL(SETTING_PAGE),
      });
      sendResponse({ success: true });
    } else if (message.action === ACTION_APPLY_SCHEDULE) {
      const data = await getStorage([
        STORAGE_SCHEDULE_ENABLED,
        STORAGE_SCHEDULE_START,
        STORAGE_SCHEDULE_END,
      ]);
      await this.applySchedule(data);
      sendResponse({ success: true });
    } else if (message.action === ACTION_OPEN_XHS) {
      const lang = message.lang;
      const domain = lang === "zh" ? XHS_DOMAIN_ZH : XHS_DOMAIN_EN;
      Filter.openAppWindow(`https://${domain}`);
      sendResponse({ success: true });
    }
  }
Readable equivalent of the constantsassets/js/constants.js
export const DL_API_URL =
  "https://api.old-panda.com/image/xiaohongshu/?post_id=";
export const ACTION_GET_DL_DATA = "getDlData";
05EvidenceTHIRD PARTY LIST
External hosts involved in this download path
  • api.old-panda.com

    Receives the Xiaohongshu post ID and xsec_token in the query string and returns media metadata for the extension's download workflow.

  • www.xiaohongshu.com

    Source page where the extension content script reads the post URL when the download button is clicked.

  • www.rednote.com

    Alternate source page domain accepted by the same content-script download function.

Data recipients

api.old-panda.comtranslate.googleapis.com
Updated 17 September 2026kdbmbkoigckegcfgcfmfpdkbbnhjcooo