Is 夸克搜题 safe?
夸克搜题 is low risk. After the Quark result iframe loads, a page-content request makes the content script send the page URL, HTML, user ID, and session ID to the vt.quark.cn iframe via postMessage. No live reply was captured; the iframe never finished loading.…
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Page HTML can be returned to a Quark iframe
After the Quark result iframe loads, a page-content request makes the content script send the page URL, HTML, user ID, and session ID to the vt.quark.cn iframe via postMessage.
No live reply was captured; the iframe never finished loading.
You start the extension's screenshot-search flow on a web page.
Dynamic analysis confirmed that the result-panel component can be mounted on a Wikipedia page.
The extension opens a Quark iframe that can ask the content script for the page body and URL.
When the iframe sends the page-content request, the content script replies with the encoded HTML body, page URL, user ID, and session ID.
| Field | Value | Why it matters | |
|---|---|---|---|
Current page URL | https://en.wikipedia.org/wiki/Example (illustrative) | This tells the iframe which site and page you had open when the result panel requested page content. | |
Page HTML body | %3Cmain%3E%3Ch1%3EExample%20page%3C%2Fh1%3E%3Cform%3E%3Cinput%20name%3D%22search%22%3E%3C%2Fform%3E%3C%2Fmain%3E encoded with base64 (illustrative) | This can include page text, links, form markup, and other content from the site you are viewing. | |
User ID | - | This can link the page-content reply to a signed-in Quark account when that account value is available. | |
Session ID | 7d6f3a38c9f944c5a6d8f4c21b2e9a10 (illustrative) | This ties the page-content reply to the result-panel session that requested it. |
Result iframe handler that packages page HTML
J = (props) => {
const { dataSource: dataSource } = props;
const iframeUrl = `${D.soutiHomeResultPage}&souti_from=${encodeURIComponent(dataSource && dataSource.soutiFrom || "")}`;
const iframeRef = E.useRef(null);
const [loaded, setLoaded] = E.useState(false);
const [shortcut, setShortcut] = E.useState(null);
E.useEffect(() => {
if (loaded) {
P().then(historyList => {
iframeRef.current?.contentWindow?.postMessage({
type: "souti_ext_result",
product: dataSource && dataSource.product || "",
text: dataSource && dataSource.text || "",
fullImage: dataSource && dataSource.fullImage ? decodeURIComponent(dataSource && dataSource.fullImage || "") : "",
imageUrl: dataSource && dataSource.imageUrl,
menuType: dataSource && dataSource.menuType,
tabUrl: dataSource && dataSource.tabUrl,
soutiFrom: dataSource && dataSource.soutiFrom,
userInfo: dataSource && dataSource.userInfo,
historyList: historyList,
isQuarkPC: dataSource && dataSource.isQuarkPC
}, "*");
});
M();
}
}, [loaded]);
E.useEffect(() => {
chrome.runtime.sendMessage(JSON.stringify({ action: L.GET_SHORTCUT_KEY, payload: {} }), function(response) {
const shortcutName = response?.payload?.commands?.find(command => command.name === "screentshot-souti")?.shortcut;
if (shortcutName) setShortcut(shortcutName);
});
}, []);
E.useEffect(() => {
window.addEventListener("message", event => {
const { data } = event;
const { type, payload, historyList } = data || {};
if (type === "souti_h5_click_close") {
closePanel();
} else if (type === "souti_h5_login_success") {
chrome.runtime.sendMessage(JSON.stringify({ action: L.LOGIN_SUCCESS, payload: { ...payload } }), function(response) {
console.log("[ login success response ] >");
});
} else if (type === "souti_h5_update_history_list") {
Q(historyList);
}
});
}, []);
const M = () => {
window.addEventListener("message", event => {
const { data } = event;
const { type, extra } = data || {};
if (type === "souti_web_dom_collect") {
const htmlInfo = {
site_url: encodeURIComponent(dataSource?.tabUrl || ""),
content: window.btoa(encodeURIComponent(document.getElementsByTagName("body")[0].innerHTML)),
uid: dataSource?.userInfo?.uId || "-",
chid: extra?.chid
};
iframeRef.current?.contentWindow?.postMessage({
type: "souti_web_dom_collect_done",
htmlInfo: htmlInfo
}, "*");
}
});
};
const removePanel = () => {
const node = document.getElementById("qk-souti-ext-result-frame");
if (node) node.remove();
};
const closePanel = () => { removePanel(); };
const again = () => {
chrome.runtime.sendMessage(JSON.stringify({ action: L.CAPTURE_AREA_SCREENSHOT_AGAIN, payload: {} }), function(response) {
console.log("[ result response ] >");
});
};
const onLoad = () => { setLoaded(true); };
return p.jsxs("div", {
className: "souti-result",
children: [
p.jsx("div", {
className: "souti-result-iframe",
children: p.jsx("iframe", {
id: "qk-souti-ext-result-frame",
onLoad: () => onLoad(),
ref: iframeRef,
src: iframeUrl,
width: "100%",
height: "100%",
style: { border: 0, width: "100%", height: "100%" }
})
}),
p.jsx("div", {
className: "souti-result-footer",
children: p.jsx("div", {
className: "souti-result-btn",
onClick: () => again(),
children: p.jsxs("label", {
className: "souti-result-btn-label",
children: ["继续截屏搜题", shortcut ? `(快捷键:${shortcut})` : ""]
})
})
})
]
});
};- vt.quark.cn
Hosts the result-panel iframe loaded by the extension and is the iframe origin that receives the page-content postMessage reply.
Screenshot + page HTML uploaded to Quark servers in multi-screen mode
Dynamic analysis captured the extension sending a screenshot and stripped HTML of the active tab to page-souti.myquark.cn when the shortcut is pressed in multi-screen mode.
Each upload includes the page URL and a persistent device ID.
You press the screenshot shortcut while multi-screen mode is enabled.
The extension's chrome.commands listener fires for the 'screentshot-souti' command.
The extension captures a screenshot, extracts the full page HTML, and uploads both to page-souti.myquark.cn, along with the page URL and a persistent device identifier.
The upload happens in the background with no in-page notification.
| Content-Type | multipart/form-data |
-- boundary --
Content-Disposition: form-data; name="imgFile"; filename="tmp_crop_img_3a1f9b2c4e.jpeg"
Content-Type: image/jpeg
[JPEG screenshot data, ~29 KB]
-- boundary --
Content-Disposition: form-data; name="reqJson"
Content-Type: application/json
{"chid":"a3f21c9d4b8e","websiteUrl":"https://example.com/account/settings","content":"PGh0bWw+PGhlYWQ+...[base64 stripped HTML]","timestamp":1748991234567,"ut":"","kp":"","pcUserCode":"061d225c-6a88-44ce-b4ee-ae0285965afbp4j3t6e4"}
-- boundary --| Field | Value | Why it matters | |
|---|---|---|---|
Device identifier (pcUserCode) | 061d225c-6a88-44ce-b4ee-ae0285965afbp4j3t6e4 | A persistent UUID generated on first install and stored in sync storage. Allows Quark to link all your uploads across sessions and devices. | |
Page URL (websiteUrl) | https://example.com/account/settings | The full URL of the browser tab that was active when you pressed the shortcut. | |
Stripped page HTML (content) | PGh0bWw+PGhlYWQ+PHRpdGxlPkFjY291bnQgU2V0dGluZ3M8L3RpdGxlPjwvaGVhZD4... | The visible HTML structure of the active page, text and links, with scripts, styles, and media removed. Base64-encoded before transmission. | |
Session ID (chid) | a3f21c9d4b8e47f2 | A per-upload UUID that ties the screenshot and JSON blob together on the server. | |
Timestamp | 1748991234567 | Unix millisecond timestamp of when you pressed the shortcut. |
Service worker upload function (chunk-a2b8f622.js:2009-2054)
// Br(onShortcutPressed, getPcUserCode) — registers the keyboard-shortcut handler
const Br = (onShortcutPressed, getPcUserCode) => {
chrome.commands.onCommand.addListener(async commandName => {
const captureMode = await getCaptureMode();
if (captureMode === CaptureMode.SCREEN && commandName === 'screentshot-souti') {
// Normal mode: area-select screenshot, no upload
onShortcutPressed();
sendMessage({ action: Action.CAPTURE_AREA_SCREENSHOT, payload: { soutiFrom: '快捷键截屏' } });
} else if (captureMode === CaptureMode.MULTI_SCREEN && commandName === 'screentshot-souti') {
// Multi-screen mode: capture + upload full page content
const [pageUrl, screenshotDataUrl, rawHtml = ''] = await Promise.all([
getActiveTabUrl(), // rt()
captureVisibleTab(), // vt()
getActiveTabHtml() // Jt() — chrome.scripting.executeScript → outerHTML
]);
// Strip scripts, styles, media tags; keep visible text + links
let strippedHtml = '';
if (rawHtml) {
strippedHtml = rawHtml
.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '')
// ... (additional tag removals)
}
const form = new FormData();
form.append('imgFile', toFile(screenshotDataUrl)); // JPEG screenshot
const payload = {
chid: generateUUID().replace(/-/g, ''), // per-upload session ID
websiteUrl: pageUrl,
content: base64Encode(strippedHtml), // stripped HTML, base64
timestamp: Date.now(),
ut: '',
kp: '',
pcUserCode: await getPcUserCode() // persistent device UUID from sync storage
};
form.append('reqJson', new Blob([JSON.stringify(payload)], { type: 'application/json' }));
axios.post(`${CONFIG.SOUTI_HOST}/api/cross_screen/screenshot/upload`, form, {
timeout: 15000,
headers: { 'Content-Type': 'multipart/form-data' }
});
}
});
};- page-souti.myquark.cn
Receives the screenshot (JPEG) and page content (stripped HTML + URL + device ID). Operated by Quark (UCWeb / Alibaba Group).
What it can do
Permissions this extension asks for, as declared in version 0.3.0. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Read and change your data on every site you visit
<all_urls> and 2 more
Read and change your data on every secure site you visit
https://*/*
Add items to the right-click menu
contextMenus
Store an unlimited amount of data in your browser
unlimitedStorage
Act on the current tab, but only after you click the extension
activeTab
See the address and title of every tab you have open
tabs
Capture the video and audio of a tab
tabCapture
Store data in your browser
storage
Run its own code inside the pages you visit
scripting
See every page you navigate to, as you navigate to it
webNavigation