Is Alitools Shopping Assistant safe?
Alitools is high risk. We observed Alitools posting a navigation event to api-dbh1-alitools.com/analytics/events, naming Amazon's domain and host. A surfmonitor path can add targetUrl/referrerUrl when enabled remotely; queued locally but never seen leaving.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Shopping-site visits sent to Alitools analytics
We observed Alitools posting a navigation event to api-dbh1-alitools.com/analytics/events, naming Amazon's domain and host.
A surfmonitor path can add targetUrl/referrerUrl when enabled remotely; queued locally but never seen leaving.
You browse to a shopping site that matches the extension's configuration.
The extension reports the visited domain and host to Alitools analytics.
A separate remote-configuration path can queue the target URL and prior tab URL, but that path was not observed in captured outbound traffic.
{
"name": "stats-task-1",
"version": 2,
"payload": {
"name": null,
"domain": "amazon.com",
"host": "www.amazon.com"
}
}| Field | Value | Why it matters | |
|---|---|---|---|
Visited domain | amazon.com | Shows which shopping site you visited. | |
Visited host | www.amazon.com | Shows the exact host name within that site. | |
Event name | stats-task-1 | Identifies this as the extension's shopping-site navigation analytics event. | |
Target URL | https://www.aliexpress.com/ (illustrative) | Can identify the specific page you opened when the separate remote-configured path is enabled. | |
Referrer URL | https://www.google.com/ (illustrative) | Can show which prior page led to the current tab when the separate remote-configured path is enabled. |
The background code that builds and sends the navigation events
const u = ["aui", "surfmonitor", "screenview", "multitools", "favorites.action"],
l = ["daily-ping", "stats-task-1", "stats-task-4", "promocode-input", "update", "install"];
async function T(e) {
if ("chrome" !== _.U1) return !0;
const t = await (0, n.mi)(),
s = await (0, n.gn)(),
r = await (0, n.Se)();
return u.includes(e) ? t && s : l.includes(e) ? t && r : t && s && r
}
function E(e, t, s) {
if ((0, o.ZB)()) try {
T(e).then((a => {
a && (0, r.jw)({
name: e,
version: t,
payload: s
})
}))
} catch (e) {
console.error(e)
} else(0, r.bN)(r.v6, {
name: e,
version: t,
payload: s
})
}
async function m(e, t, s, n) {
if ((0, o.ZB)()) try {
n || (n = await async function() {
const e = await (0, i.Qr)(i.do.SERVER_TIME_DIFF);
return (0, c.f5)(new Date, e).toISOString()
}()), T(e).then((async r => {
r && await (0, a.LC)({
name: e,
version: t,
payload: s,
timeCreated: n
})
}))
} catch (e) {
console.error(e)
} else(0, r.bN)(r.i0, {
name: e,
version: t,
payload: s
})
}function u(e) {
(0, r.L)((0, a.rk)({
url: "/analytics/events",
method: "POST",
json: e
}))
}
function l(e) {
(0, r.L)((0, a.rk)({
url: "/analytics/events/batch",
method: "POST",
json: e
}))
}async function o() {
return await (0, a.Qr)(a.do.AT_BATCH) || []
}
async function i(e) {
const t = await (0, r.W)("eventsBatchLimitSize");
let s = [...await o()];
if (s.length >= t) {
const r = s.length - t + 1;
s = s.slice(r).concat(e)
} else s = s.concat(e);
let i = await (0, r.W)("eventsBatchTriggerSize");
try {
await (0, a.Lk)(a.do.AT_BATCH, s)
} catch (e) {
i = s.length
}
s.length >= i && await (0, n.G)()
}
async function c() {
await (0, a.Lk)(a.do.AT_BATCH, [])
}async function E(e) {
if (!await (0, n.W)("statsTask2")) return;
if (!await async function(e) {
const t = await (0, n.W)("statsTask2Urls");
let s = !1;
for (const r of t) {
const t = r.d;
if (e.includes(t)) {
s = !0;
break
}
}
if (s) {
const s = (0, o.QY)(e);
for (const e of t) {
if (s === e.d) return !0
}
}
return !1
}(e.targetUrl)) return;
const t = u(u({}, e), {}, {
domain: (0, o.QY)(e.targetUrl)
});
(0, a.L)((0, i.G)("surfmonitor", 1, t))
}async function c(e) {
if (0 !== e.frameId) return;
await (0, r.W)("statsTask1") && await async function(e, t) {
if (!e.timeStamp || !e.tabId || !e.url) return;
const s = await async function() {
return await (0, i.Qr)(i.do.AV_PREVIOUS_EVENTS) || []
}();
for (const t of s)
if (t.tabId === e.tabId) {
if (t.timeStamp === e.timeStamp) return;
if (t.url === e.url && e.timeStamp - t.timeStamp < 5e3) return;
if (t.tabId === e.tabId) break
} s.unshift(e), s.length > 5 && s.pop();
await async function(e) {
await (0, i.Lk)(i.do.AV_PREVIOUS_EVENTS, e)
}(s), t()
}(e, (async () => {
try {
await async function(e) {
const t = await (0, r.W)("statsTask1Urls"),
s = (0, o.G)(t, e);
if (!s) return;
const i = s.n || null,
c = (0, a._P)(e),
_ = (0, a.QY)(e);
(0, n.ch)("stats-task-1", 2, {
name: i,
domain: _,
host: c
})
}(e.url)
} catch (e) {
console.error(e)
}
}))
}- api-dbh1-alitools.com
Receives the confirmed stats-task-1 analytics POST containing the visited domain and host.
- api.alitools.io
Configured as the extension's base API host; the code posts analytics events to /analytics/events and /analytics/events/batch under the API base.
- cnf-u45p-alitools.com
Provides remote configuration values such as statsTask1, statsTask1Urls, statsTask2, and statsTask2Urls.