Is Ali Lens with Product Search By Image safe?

Medium risk

Ali Lens records the URL, title, and time spent on every site you visit and sends it to fulhar.com.

A content script that runs on every page you visit (not just AliExpress) records the page URL, title, referrer, and visible time, tagging each event with a persistent per-install ID and sending it in batches to fulhar.com. Tracking is on by default and is only disclosed in a collapsed accordion inside the extension's side panel. Separately, on any non-Amazon site, the extension rewrites Amazon product links so clicks route through fulhar.com first, which attaches the developer's own affiliate tag before forwarding you to the product page.

readyandmakesv3.0.7Chrome Web Store
49Risk
Who publishes it

readyandmakes - 6 other listings from the same operator, 1 of them carrying a finding

What this publisher told the store about itself, and the other listings that told it the same thing.

Publisher
readyandmakes

AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.

Publishers can request a review.

Findings

Ali Lens tracks every website you visit, not just AliExpress, and sends it out

HighunwantedCWE-359Static analysis

Code analysis shows the extension records the full URL, title and referrer of every page you visit, not only AliExpress, and sends it to fulhar.com tagged with a persistent per-install id.

What actually happens

You did this

You load any page in your browser, not just an AliExpress page.

The tracker's manifest match pattern is http://*/* and https://*/*, so it runs on every top-level site you visit.

The extension did this

The extension records the page's full URL, title and referrer, then the background worker batches and sends it to fulhar.com.

This runs on every http or https page while tracking defaults to on; switching it off requires opening a collapsed section of the side panel.

What each page-view event carries

  • Full page address
    https://news.example.com/account/settings?token=9f2a1c

    The exact page you're on, including anything after ? or # such as search terms or account ids in the URL.

  • Page title
    Online Banking - Account Summary

    The <title> of the page, giving readable context about what you were doing there.

  • Referrer
    https://www.google.com/search?q=mortgage+refinance+rates

    The page you came from, which can reveal a search query or another site you were just on.

  • How long you looked at the page
    184000

    Time the page was actually visible to you, not just open in a background tab.

  • Persistent install id
    6e2b6f2a-7a41-4c9d-9c2e-0a6b8d2f5e11

    A random id created when you installed the extension, sent with every event so your visits across every site can be tied together over time.

  • Browser language and time zone
    en-US, America/Chicago

    Your browser's language setting and time zone, added to every event.

The code that does this

This code ships human-readable, with no minification or obfuscation to reverse

Readable version

tracker.js: builds and sends a page-view event on every http/https page

tracker.js
function send(final) {    if (!view) return;    // Fold in whatever visible time has run since the last accounting, so the    // number sent is correct whether the page is visible or not right now.    var visible = view.visibleMs;    if (view.visibleSince) visible += Date.now() - view.visibleSince;    var event = {      event_id: view.id,      url: view.url,      title: (document.title || '').slice(0, 512),      referrer: view.referrer,      session_id: view.session,      started_at: new Date(view.startedAt).toISOString(),      duration_ms: Math.round(visible),      timezone: timezone(),      language: (navigator.language || '').slice(0, 32),    };    if (final) event.ended_at = new Date().toISOString();    try {      // The worker may be asleep; waking it can fail while the tab is being      // torn down, and a lost page view is not worth an error in the console      // of somebody else's site.      chrome.runtime.sendMessage({ type: 'ap-track', event: event, final: !!final },        function () { void chrome.runtime.lastError; });    } catch (e) {}  }

tracker-bg.js: batches events and POSTs them tagged with a persistent visitor id

tracker-bg.js
async function apTrackFlush() {  if (apTrackSending) return;  await apTrackLoadQueue();  if (!apTrackQueue.length) return;  const settings = await apTrackSettings();  if (!settings.enabled) {    apTrackQueue = [];    await apTrackSaveQueue();    return;  }  apTrackSending = true;  const batch = apTrackQueue.slice(0, AP_TRACK_BATCH_MAX).map(function (e) {    return Object.assign(      { visitor_id: settings.visitorId, source: 'extension' }, e,      { meta: Object.assign({ app: AP_TRACK_APP }, e.meta) });  });  let sent = false;  try {    const res = await fetch(settings.endpoint + 'track/batch/', {      method: 'POST',      headers: { 'Content-Type': 'application/json' },      body: JSON.stringify({ events: batch }),    });    sent = res.status < 500;  } catch (e) {    sent = false;  }  apTrackSending = false;  if (sent) {    const done = new Set(batch.map(function (e) { return e.event_id; }));    apTrackQueue = apTrackQueue.filter(function (e) { return !done.has(e.event_id); });    await apTrackSaveQueue();    if (apTrackQueue.length) apTrackScheduleFlush();    return;  }  await apTrackSaveQueue();  try { chrome.alarms.create(AP_TRACK_RETRY_ALARM, { delayInMinutes: 1 }); } catch (e) {}}

Where the data ends up

    • fulhar.com

    Receives the batched page-view events, tagged with an app id the source comments say is shared with the vendor's 1688 extension on the same backend.

Check if you're affected

Reads this install's own tracking state directly from chrome.storage.local: whether tracking is on, the persistent visitor id, and any page views queued to be sent.

Requires
  • Chrome or Edge with Ali Lens installed
  • Developer mode enabled in chrome://extensions
check-tracking-state.js · js
chrome.storage.local.get(  ['apTrackingEnabled', 'apVisitorId', 'apTrackQueue', 'apLifeQueue'],  (store) => {    console.log('Tracking enabled:', store.apTrackingEnabled !== false);    console.log('Persistent visitor id:', store.apVisitorId);    console.log('Queued page views waiting to send:', store.apTrackQueue);    console.log('Queued lifecycle events waiting to send:', store.apLifeQueue);  });
How to run it
  1. 1Open chrome://extensions and enable Developer mode.
  2. 2Find Ali Lens, click "service worker" to open its DevTools.
  3. 3Paste this script into the Console and press Enter.
  4. 4Read the three logged values.

Observation

Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.

Where it sends data

Destinations our analysis observed Ali Lens with Product 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.

  • fulhar.com

    Ali Lens with Product Search By Image sends data to fulhar.com. One other extension we have analyzed sends data here.

Updated 30 September 2026gpplenaolkhneojcnohhekpekencapao