Is Cently: Automatic Coupons + Cashback for Free safe?
Cently is medium risk. Cently stores remote checks for rival extensions under installedExtensions; Rakuten, Coupert, Capital One were false in the test run. It fetches selectors from eb.nextgenshopping.com/flags and sends comp_ext in Snowplow data.
Who publishes itNextGen Shopping LLC - no other listings under this identity
NextGen Shopping LLC - no other listings under this identity
What this publisher told the store about itself, and the other listings that told it the same thing.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Cently records other-extension detection results
Cently stores remote checks for rival extensions under installedExtensions; Rakuten, Coupert, Capital One were false in the test run.
It fetches selectors from eb.nextgenshopping.com/flags and sends comp_ext in Snowplow data.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-200
- Source
- Dynamic sandbox
You browse a page where Cently's content script is active.
The extension manifest registers contentScript.js for both HTTP and HTTPS pages at document_start.
The extension checks remote-provided selectors for named shopping extensions and records the results.
In the observed run, extension storage received Rakuten, Coupert, and Capital One entries set to false.
The code reads installedExtensionsDetectionConfig from the flags response; no request body is used for this GET.
This records whether Cently's selector checks matched named browser extensions in your browsing environment.
- Location
- chrome.storage.local key 'installedExtensions'
{ "installedExtensions": { "Coupert": false, "Rakuten": false, "Capital One": false }}- Detected extension mapinstalledExtensions: { Rakuten: false, Coupert: false, Capital One: false }
Shows which named extensions the selector checks did or did not find in your browser environment.
- Detected extension listcomp_ext: []
Lists the names that had a true detection result when telemetry is assembled.
- Extension versionext_version: 7.43.0
Adds the installed Cently version to the same telemetry entity, helping group results by release.
- Installation sync IDinstallation_sync_id: e3547d61-6ad0-4ff6-9d40-2b3fdb8c7d23 (illustrative; the observed value began with e354)
Adds a stable installation identifier alongside the extension-detection list.
Observed telemetry included Snowplow user-entity data with ext_version '7.43.0', comp_ext [], and an installation_sync_id value.
The shipped code checks selectors, stores results, then reads true entries into telemetry.
Selector-based extension detection
contentScript.jslet Hb = class { constructor(e, t, n) { this.logger = e, this.flags = t, this.storageHandler = n, e.useScope("content:InstalledExtensionsDetection") } detectExtensions() { return e = this, t = void 0, r = function*() { const e = yield this.flags.valueOf(Ho.A.InstalledExtensionsDetectionConfig); if (!e) return void this.logger.warn(`Unable to retrieve ${Ho.A.InstalledExtensionsDetectionConfig} config. \n Installed extensions detection by DOM will not start.`); const { detectionInfo: t } = e; if (!Array.isArray(t) || 0 === t.length) return; const n = {}; t.forEach(e => { if ("selector" === e.type) { const t = this.querySelectorAllShadows(e.selector).length > 0; n[e.name] = t } return [] }), yield this.storageHandler.append(n), this.logger.debug("Installed extensions detection by DOM finished.") }, new((n = void 0) || (n = Promise))(function(o, i) { function a(e) { try { c(r.next(e)) } catch (e) { i(e) } } function s(e) { try { c(r.throw(e)) } catch (e) { i(e) } } function c(e) { var t; e.done ? o(e.value) : (t = e.value, t instanceof n ? t : new n(function(e) { e(t) })).then(a, s) } c((r = r.apply(e, t || [])).next()) }); var e, t, n, r } querySelectorAllShadows(e, t = window.document) { if (!t) return []; const n = Array.from(t.querySelectorAll("*")).map(e => e.shadowRoot).filter(Boolean).flatMap(t => this.querySelectorAllShadows(e, t)); return Array.from(t.querySelectorAll(e)).concat(n) }};Local storage handler for detection results
contentScript.jsconst c = "installedExtensions";let l = class { constructor(e) { this.cacheFactory = e, this.storage = this.cacheFactory(o.$.Local) } append(e) { return s(this, void 0, void 0, function*() { const t = yield this.get(); yield this.storage.set(c, Object.assign(Object.assign({}, t), e)) }) } get() { var e; return s(this, void 0, void 0, function*() { return null !== (e = yield this.storage.get(c)) && void 0 !== e ? e : {} }) } getList() { return s(this, void 0, void 0, function*() { return Object.entries(yield this.get()).flatMap(([e, t]) => t ? [e] : []) }) }};Snowplow user entity includes comp_ext
background.jsfunction An() { var e; return wn(this, void 0, void 0, function*() { const t = QU().get(y.Flags); if (!(null === (e = yield t.valueOf(v.SnowplowToggle)) || void 0 === e ? void 0 : e.enabled)) return { schema: "", data: {} }; const n = QU().get(Ve.AccountDetails), r = QU().get(Ve.PopupAuthentication), o = QU().get(kn.InstalledExtensionsStorageHandler), i = yield QU().get(Xe.UserId).get(), { id: a } = yield n.all(), s = { member_id: (yield r.isAuthenticated()) ? a : void 0, ext_version: Te(), comp_ext: yield o.getList(), installation_sync_id: i, cf_user_name: void 0, is_logged_in_to_amazon: void 0 }; return (0, Dt.BK)(Dt.$L.User, Cn.r, s) })}- eb.nextgenshopping.com
Provides the remote flags endpoint that can include installedExtensionsDetectionConfig.
- c.couponfollow.com
Receives Snowplow telemetry containing the comp_ext user-entity field.