Is PikPak Browser Extension safe?
PikPak is high risk. PikPak Browser Extension injects its analytics SDK into non-Chrome tabs after tab updates. The SDK fires an image-beacon to rcv5-sp.mypikpak.com with an encrypted log built from page URL, title, referrer, and browser/screen details.…
Who publishes itPIKCLOUD PTE. LTD. - no other listings under this identity, 2 shared hostnames
PIKCLOUD PTE. LTD. - no other listings under this identity, 2 shared hostnames
What this publisher told the store about itself, and the other listings that told it the same thing.
Shared hosts - 2 hostnames
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
Every page URL is sent to PikPak analytics
PikPak Browser Extension injects its analytics SDK into non-Chrome tabs after tab updates.
The SDK fires an image-beacon to rcv5-sp.mypikpak.com with an encrypted log built from page URL, title, referrer, and browser/screen details.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Dynamic sandbox
You open or navigate a web page in a tab.
The extension injects an analytics SDK that reads page context and sends an encrypted beacon to rcv5-sp.mypikpak.com.
Image beacon request observed during dynamic analysis; no response body was recorded.
- Current page URLhttps://account.example.com/settings?tab=security (illustrative)
Shows the exact page you were viewing when the tab update happened.
- Page titleAccount Security Settings (illustrative)
Can reveal the name or topic of the page even when the address is less descriptive.
- Referrerhttps://search.example.com/results?q=cloud+storage (illustrative)
Shows the page that led to the current page when the browser exposes it.
- Tracking ID8b1a9953c4611296a827abf8c47804d7 (illustrative)
Lets repeated page views from the same browser be linked together.
- Browser and screen detailsChrome/126 on 1920x1080, 24-bit color, en-US (illustrative)
Adds device context such as browser version, screen size, color depth, and language.
The service worker injects the analytics SDK, which encrypts and sends the page context
Tab-update listener and readable injection handler
deobfuscated/background.jschrome.tabs.onUpdated.addListener(r.Pc)const L = async (e, a, t) => { try { if (!a.status || t.url?.startsWith("chrome")) return; await chrome.scripting.executeScript({ target: { tabId: e }, files: ["content.js", "ppa.min.js"] }) } catch (e) { console.log(e) }}Readable analytics configuration and collected fields
deobfuscated/ppa.min.jsvar r = n(2), i = t.exports = { v: "2.0.1", furl: "//rcv5-sp.mypikpak.com/api/stat/rt/js", appid: "30211", s: "57b07219c2aa11fe1e327dedb0bf8742", comm: { ai: null, dm: window.realdomain || document.domain, ul: document.URL, tt: document.title, sn: window.screen.width + "x" + window.screen.height, cd: window.screen.colorDepth, rr: document.referrer, rf: r.getReferfrom() || "", ua: navigator.userAgent, lg: navigator.language, ci: r.getCookieId(), ed: {} }, extend: function(t) { return i.comm.ed = r.deepExtend({}, i.comm.ed, t), i.comm }, config: function(t, e, n, i) { this.appid = t, this.comm.ai = t, this.s = e, "boolean" == typeof i && (this.force = i), n && (this.event = r.unique(this.event.concat(n))) }, event: ["click"], debug: r.getParameter("debug"), force: !0 }Readable encrypted image-beacon sender
deobfuscated/ppa.min.jsfunction r(t) { s.imageBeacon(t, function() { o.debug && s.print.msg("Report success: " + t + ":)") }, function() { o.debug && s.print.err("Report error: " + t + ":(") })}var i = n(3), o = n(1), s = n(2), a = "JSON" in window ? JSON : n(71), u = [], c = function(t) { var e, n, r, u = o.furl; e = 1 === t.length ? s.deepExtend({}, o.comm, t[0]) : s.deepExtend({}, o.comm, { il: t }), e = a.stringify(e); var c = i("mypikpak"), f = c.slice(6, 22); const h = s.aesEncrypt(e, c, f), l = a.stringify({ _crypt_data: h }); return n = "appId=" + o.appid + "log=" + l + "v=" + o.v, r = i(n + o.s), u + "?appId=" + o.appid + "&log=" + encodeURIComponent(l) + "&v=" + o.v + "&sig=" + r }, f = "";t.exports = function(t) { var e; e = !1 === t.force ? t.force : o.force, delete t.force, u.push(s.deepExtend({}, t, { tm: Math.round((new Date).getTime() / 1e3) })), o.debug && s.print.msg("Report has been push into queue: " + a.stringify(t)); var n = c(u); n.length > s.getBroswer() ? 1 === u.length ? (s.print.err("Report error: your single report is too long."), u = []) : (r(f), u.splice(0, u.length - 1), e && r(c(u))) : e ? (r(n), u = []) : f = n}Tracking ID, beacon, and AES helpers
deobfuscated/ppa.min.jsgetCookieId: function() { if (!window.cookieId) { var t = Math.random(), e = navigator.appName + "_" + navigator.appVersion + "_" + navigator.userAgent + "_" + navigator.appCodeName + "_" + navigator.platform, n = (new Date).valueOf(); window.cookieId = r(n + e + t) } return window.cookieId},imageBeacon: function(t, e, n) { t = /^\/\//.test(t) ? "https:" + t : t; var r = new Image; r.onload = e, r.onerror = n, r.src = t},aesEncrypt: function(t, e, n) { const r = s.createCipheriv("aes-256-cbc", e, n); return r.update(t, "utf8", "hex") + r.final("hex")}- rcv5-sp.mypikpak.com
Receives the encrypted analytics beacon generated by the injected ppa.min.js SDK for PikPak.
PikPak Reads Clipboard Text on Copy
Copying text on a website triggers PikPak's content script to read the full clipboard text, if clipboard-analysis is on (shipped default).
The code checks if the text looks like a magnet, torrent, media, or installer link before a prompt.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-200
- Source
- Dynamic sandbox
You copy text on a webpage.
The extension has injected its content script into regular pages through its broad host permission.
PikPak reads the clipboard text and checks whether it looks like a downloadable link.
If a download-looking value matches, it opens a PikPak save prompt; no clipboard-content upload endpoint was identified for this claim.
- Full clipboard textmagnet:?xt=urn:btih:0123456789abcdef0123456789abcdef01234567&dn=ubuntu-24.04-desktop-amd64.iso (illustrative)
The extension reads the complete clipboard text when the copy handler runs, before deciding whether it's useful to PikPak.
- Download-link matchhttps://archive.org/download/sample-video-file/sample.mp4 (illustrative)
The extension keeps values that look like magnet links, torrent files, media files, archives, installers, or similar downloadable URLs.
Clipboard analysis defaults on; the content script reads the clipboard inside the copy handler.
Default options enable clipboard analysis
content.jsconst k = Object.freeze({ [s.MAIN_CONTROL]: !0, [s.INSERT_BUTTON_CONDITION]: i.AUTO, [s.SELECTED_INSERT_BUTTON_SETTING]: !1, [s.ANALYZE_CLIPBOARD_CONTENT]: !0, [s.ANALYZE_BROWSER_DOWNLOAD_CONTENT]: !0, [s.LAST_SELECT_FOLDER]: "My Links", [s.MEDIA_INSERT_BUTTON_SETTING]: !0, [s.MEDIA_INSERT_BUTTON_CONDITION]: o.AUTO, [s.SHOW_FLOAT_BALL]: r.AS_NEED})Download-link matcher used after the clipboard read
content.jsclass oe extends ee { static { this.SOURCE_LINK_REGEX = /((magnet:\?|ftp:\/\/|thunder:\/\/|ed2k:\/\/)\S{3,})|((magnet:\?|https?:\/\/|ftp:\/\/|thunder:\/\/|ed2k:\/\/)[^=?&\s]+\.(torrent|mp4|rar|7z|zip|rmvb|mkv|avi|iso|exe|dmg))/gi } constructor() { super(n.SELECTION), this.hide() } static computedTopRightOfSelectionRange(e) { const n = Array.from(e), t = Math.min(...n.map(e => e.top)), a = Math.max(...n.filter(e => e.top === t).map(e => e.right)); return { top: Math.max(window.scrollY + t - this.ICON_SIZE, 0), left: a - this.ICON_SIZE } } static init() { const e = new this, n = n => { te(n) || e.hide() }, t = n => { te(n) || e.show() }; return { enable() { e.show(), document.addEventListener("mousedown", n), document.addEventListener("mouseup", t) }, disable() { document.removeEventListener("mousedown", n), document.removeEventListener("mouseup", t) } } } setPosition(e) { const { top: n, left: t } = oe.computedTopRightOfSelectionRange(e.getRangeAt(0).getClientRects()); return this.button.style.position = "absolute", this.button.style.top = `${n}px`, this.button.style.left = `${t}px`, this } hide() { return this.setDisplayStyle("none") } show() { const e = window.getSelection(), n = e?.toString()?.match(oe.SOURCE_LINK_REGEX)?.filter(ie); return e && n && n.length ? (R.web_plugin_save_button_show({ scene: d.SELECT }), this.setSourceLinks(n).setPosition(e).setDisplayStyle("block").appendToBody()) : this }}Copy handler reads the clipboard before matching
content.jsasync copy() { try { if (Un()) return; if (!(await Ye(a.OPTIONS_SETTING))?.[a.OPTIONS_SETTING][s.ANALYZE_CLIPBOARD_CONTENT]) return; const e = await navigator.clipboard.readText(); if (Hn === e) return; Hn = e; const n = e.match(oe.SOURCE_LINK_REGEX); if (!n) return; Wn.show(n, { scene: d.CLIPBOARD }) } catch (e) { console.log("Failed to read clipboard contents: ", e) }}Background script injects content.js into updated tabs
background.jsL = async (e, a, t) => { try { if (!a.status || t.url?.startsWith("chrome")) return; await chrome.scripting.executeScript({ target: { tabId: e }, files: ["content.js", "ppa.min.js"] }) } catch (e) { console.log(e) }}