Is Qoala: Cashback y Cupones Automaticos safe?
Qoala is high risk. When the cashback flow opens a tracking link, the extension posts destination URL and prior page to Qoala's tracker, with signed-in user ID when present, anonymous_id, advertiser metadata, platform, and version; unobserved without login.…
Who publishes itJOIN QOALA SL. - no other listings under this identity, 1 shared hostname
JOIN QOALA SL. - no other listings under this identity, 1 shared hostname
What this publisher told the store about itself, and the other listings that told it the same thing.
Shared hosts - 1 hostname
Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Cashback action sends page URL to Qoala
When the cashback flow opens a tracking link, the extension posts destination URL and prior page to Qoala's tracker, with signed-in user ID when present, anonymous_id, advertiser metadata, platform, and version; unobserved without login.
You open a cashback tracking link from the extension flow.
The extension sends the page you were on, the destination link, and account or offer metadata to Qoala's click-tracking service.
| Content-Type | application/json |
| Field | Value | Why it matters | |
|---|---|---|---|
Destination link | https://www.elcorteingles.es/ (illustrative) | Shows the cashback or shopping link the extension is about to open for you. | |
Current page URL | https://www.joinqoala.com/es/tiendas/el-corte-ingles (illustrative) | Shows the page where you started the cashback action, adding browsing context to the request. | |
Signed-in user ID | 839204 (illustrative) | Lets the service connect the click event to your Qoala account when you are signed in. | |
Anonymous identifier field | "" (empty in this code path) | Provides a separate tracking field in the request, although this code path passes it as empty. | |
Offer and advertiser data | host=elcorteingles.es; network_id=awin; advertiser_name=El Corte Ingles (illustrative) | Describes which cashback offer, advertiser, network, and store host the click belongs to. | |
Extension platform | platform=chrome-extension; version=5.0.0 | Shows that the click came from the Chrome extension and which extension version sent it. |
The content script carries the current page URL into the click-tracking POST
class _ {
static create(t) {
return e = this, n = void 0, i = function*() {
return yield a.fetch("https://qoala-linktrack-prod-7adzuf62ma-no.a.run.app/clicks", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
url: t.url,
current_url: t.current_url,
uid: t.uid,
anonymous_id: t.anonymous_id,
deal_id: t.offer_id,
host: t.host,
network_id: t.network_id,
advertiser_id: t.advertiser_id,
advertiser_name: t.advertiser_name,
context: t.context,
platform: "chrome-extension",
session: "",
version: "5.0.0"
})
})
}, new((o = void 0) || (o = Promise))((function(t, r) {
function c(t) {
try {
s(i.next(t))
} catch (t) {
r(t)
}
}
function a(t) {
try {
s(i.throw(t))
} catch (t) {
r(t)
}
}
function s(e) {
var n;
e.done ? t(e.value) : (n = e.value, n instanceof o ? n : new o((function(t) {
t(n)
}))).then(c, a)
}
s((i = i.apply(e, n || [])).next())
}));
var e, n, o, i
}
}class P {
static open(t, e = !1) {
return S(this, void 0, void 0, (function*() {
return c.send(i, {
url: t,
pinned: e
})
}))
}
static redirectFromWindowContext(t, e) {
window && (console.info("Redirecting from window context", t, e), e ? window.location.href = t : window.open(t))
}
static openTrackingUrl(t, e, n = !0, o = !1) {
var r;
return S(this, void 0, void 0, (function*() {
const a = yield k.get();
let s = {
id: "",
url: t,
redirect_url: t
};
try {
s = yield _.create({
url: t,
current_url: e.current_url,
uid: null !== (r = null == a ? void 0 : a.uid) && void 0 !== r ? r : "",
anonymous_id: "",
host: e.host,
network_id: e.network,
advertiser_id: e.advertiser_id,
advertiser_name: e.advertiser_name,
context: e.context,
offer_id: e.offer_id
})
} catch (t) {
console.log(t)
}
yield E.set(e.host, s.id), yield h.set("@CASHBACK_SHOW_SUCCESS_POPUP", !0), n ? (setTimeout((() => {
P.redirectFromWindowContext(s.redirect_url, n)
}), 5e3), yield c.send("@UPDATE_TAB_MESSAGE", {
url: s.redirect_url
})) : yield c.send(i, {
url: s.redirect_url,
pinned: o
})
}))
}
}window.addEventListener("message", (function(t) {
var e, n, o;
switch (t.data.id) {
case "@CASHBACK_POPUP_HIDE_MESSAGE":
const i = document.getElementById(U);
i && (i.style.visibility = "hidden");
break;
case r:
null === (e = document.getElementById(U)) || void 0 === e || e.remove(), null === (n = document.getElementById(U)) || void 0 === n || n.remove();
break;
case "@REDIRECT_POPUP_CLOSE_MESSAGE":
null === (o = document.getElementById("qla-qoala-redirect-container")) || void 0 === o || o.remove();
break;
case "@OPEN_TRACKING_URL_MESSAGE": {
const {
url: e,
data: n,
redirect: o,
pinned: i
} = t.data.payload;
(function(t, e, n = !0, o = !1) {
return R(this, void 0, void 0, (function*() {
yield P.openTrackingUrl(t, {
host: e.host,
current_url: n ? window.location.href : void 0,
network: e.network,
advertiser_id: e.advertiser_id,
advertiser_name: e.advertiser_name,
context: e.context,
category: e.category,
type: e.type,
offer_id: e.offer_id
}, n, o)
}))
})(e, n, o, i).then().catch();
break
}
}
}), !1)The background worker performs the fetch requested by the content script
case "@FETCH_REQUEST_MESSAGE":
(function(t) {
return a(this, void 0, void 0, (function*() {
const {
payload: n
} = t;
if (!n) return;
console.log("Performing fetch for Request: ", n);
const e = yield fetch(n.url, n.request);
return e.ok ? yield e.json(): void 0
}))
})(e).then((t => {
c(t)
})).catch((t => {
console.log(t)
})).finally((() => !0));
break;- qoala-linktrack-prod-7adzuf62ma-no.a.run.app
Qoala click-tracking service that receives the cashback destination URL, current page URL, user field, offer metadata, and extension version.
Dynamic analysis without a signed-in cashback account showed the extension polling Qoala APIs but did not trigger a cashback popup or record a current_url POST. The evidence for this claim is the shipped cashback-click code path rather than an organically captured request body.
What it can do
Permissions this extension asks for, as declared in version 5.0.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>
Act on the current tab, but only after you click the extension
activeTab
Schedule its own background tasks
alarms
Store data in your browser
storage