Is Xiaohongshu for Desktop safe?
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.
Who publishes itSeiri - 6 other listings from the same operator, none carrying a finding
Seiri - 6 other listings 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.
Same store account
6 other listings published from this account, 30k+ 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.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
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.
What actually happens
You click the download button that the extension adds to a Xiaohongshu or Rednote post.
The extension reads the post ID and page token from the URL and sends them to api.old-panda.com.
Values forwarded for the download lookup
- Post identifier65f1a2b3c4d5e6f7890abcde
This identifies the exact Xiaohongshu or Rednote post you chose to download.
- Post access tokenAT_eyJzaWQiOiJ4aHMiLCJub25jZSI6IjE3MTYyNjM0MDAifQ
This token is copied from the page URL and travels with the post lookup request.
- Returned media URLshttps://sns-img-qc.xhscdn.com/1040g00830vtb9apg6g005n4bq6c0j6a2tq8h6f8
The response can describe the images or videos that will be saved from that post.
- Returned title and textWeekend route notes Coffee shops and photo locations near the river
The response can include the title and written content of the post you selected.
Captured request
The service worker expects 200 OK JSON and forwards the parsed response to the content script.
- Content-Type
- application/json
The code that does this
The shipped code parses the token and forwards it to the API
Readable equivalent of the content-script parser
assets/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 handler
assets/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 constants
assets/js/constants.jsexport const DL_API_URL = "https://api.old-panda.com/image/xiaohongshu/?post_id=";export const ACTION_GET_DL_DATA = "getDlData";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.
Where it sends data
Destinations our analysis observed Xiaohongshu for Desktop 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.
- translate.googleapis.comwidely used
Xiaohongshu for Desktop sends data to translate.googleapis.com. A widely used service: 92 other extensions we have analyzed send data here.
- api.old-panda.com
Xiaohongshu for Desktop sends data to api.old-panda.com. 3 other extensions we have analyzed send data here.