Is Share-A-Cart – Easily Share Shopping Carts safe?

Medium risk

Share-A-Cart is medium risk. Creating a cart on Sam's Club or Shein makes Share-A-Cart build a GET to share-a-cart.com with site's hostname, sent at most once daily per vendor. Recorded traffic didn't exercise this; evidence is shipped code, not an observed request.…

sac-publisher-groupv3.1.17Chrome Web Store
52Risk
Who publishes it

Share-A-Cart - 3 other listings from the same operator, none carrying a finding

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

Publisher
sac-publisher-group
Declared legal entity
Share-A-Cart
Registered address
2299 E 13th Street, 6H, Brooklyn, NY 11229, US
Registered contact
Felix Shnir

Same store account

3 other listings published from this account, 44k+ users between them, none of them carrying a finding.

Shared hosts - 4 hostnames

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.

assets.share-a-cart.com
Also called by 4 other listings, including Share-A-Cart
cdn.share-a-cart.com
Also called by 4 other listings, including Share-A-Cart
crtsh.net
Also called by 4 other listings, including Share-A-Cart
share-a-cart.com
Also called by 4 other listings, including Share-A-Cart

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

Publishers can request a review.

Findings

Cart creation sends vendor hostname to Share-A-Cart

Creating a cart on Sam's Club or Shein makes Share-A-Cart build a GET to share-a-cart.com with site's hostname, sent at most once daily per vendor.

Recorded traffic didn't exercise this; evidence is shipped code, not an observed request.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-200
Source
Dynamic sandbox
What actually happens
You did this

You create a cart on Sam's Club or Shein with the extension.

The relevant path is the create-cart message handled by the background script.

The extension did this

The extension prepares a Share-A-Cart request containing the shopping site's hostname.

The code rate-limits the request to once per day for each of those two vendors.

Fields placed in the Share-A-Cart request URL
  • Shopping-site hostname
    https://www.samsclub.com

    Lets Share-A-Cart know which supported shopping site you were using when the cart was created.

  • Vendor bucket
    samsclub

    Limits the request to two vendor categories, so the request only applies when you use those supported stores.

Captured request
GEThttps://share-a-cart.com/u/https%3A%2F%2Fwww.samsclub.com

Source-derived request shape; the recorded traffic did not trigger this vendor-specific request.

The code that does this

The create-cart path calls the vendor-specific redirector request

Readable version

Readable redirector method

deobfuscated/js/background.js
performRedirectorFetch(e, t) {  if (["samsclub", "shein"].includes(e.id)) try {    const {      hostname: n    } = new URL(t), a = this.lastFetchMap.get(e.id) || -1, r = Date.now();    if (-1 === a || r > a + 864e5) {      this.lastFetchMap.set(e.id, r);      const t = `https://share-a-cart.com/u/${encodeURIComponent(`https://${n}`)}`;      fetch(t, {        mode: "no-cors"      }).catch(() => {})    }  } catch (e) {}}

Readable create-cart branch

deobfuscated/js/background.js
if ("create-cart" === n.action) {  const e = d.getVendorByURL(n.url);  let t;  return e ? (e.reader(n.url).then(({    cartID: e,    marts: n,    errorCode: a  }) => {    a ? s({      errorCode: a    }) : n ? s({      marts: n    }) : t = e  }).then(o.initialize).then(e => e.used()).then(() => {    s({      cartID: t,      vendorID: e.id,      vendorDisplayName: e.displayName    })  }).catch(t => {    l.errorToSentry(`[vendor.reader] [${e.displayName}][url=${void 0===n?"null":n.url}]`, t, {      name: e.id,      tags: {        type: "vendor",        operation: "read",        vendor: e.id      }    })  }), d.performRedirectorFetch(e, n.url)) : s({    errorCode: "2000"  }), !0}
Destination host
    • share-a-cart.com

    Receives the encoded shopping-site hostname for the Sam's Club or Shein cart creation path.

Daily remote config controls routing settings

Share-A-Cart requests https://cdn.share-a-cart.com/config.json and stores returned routing percentage, frame-use flag, and excluded vendor list.

It fetches this on startup and daily, merges it in, and writes routing/popup values locally.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-829
Source
Dynamic sandbox
What actually happens
You did this

The extension reaches its scheduled configuration check.

The alarm is created with a 1,440-minute period, and the configuration check also runs when the background service loads its settings.

The extension did this

The extension downloads a remote JSON configuration and stores returned settings locally.

Observed stored settings included routing chance, frame usage, and a vendor blocklist for the in-page popup.

When this fires

Every 1 day

The background alarm checks for remote configuration once every 24 hours, while a shorter cache prevents immediate repeat fetches.

Captured request
GEThttps://cdn.share-a-cart.com/config.json

Observed during dynamic analysis: HTTP 200, followed by local storage writes for fetched configuration settings.

Remote settings observed or controlled by the JSON config
  • Routing chance
    100

    Lets the remote config set a percentage value that the extension stores for routing behavior.

  • Frame usage
    false

    Lets the remote config choose whether frame-based routing support is enabled or disabled in local settings.

  • Popup vendor blocklist
    amazon, walmart, target, ebay, etsy

    Lets the remote config change which supported vendors are excluded from the extension's in-page popup behavior.

What's stored on your device

These local settings show which remote-controlled values were available to the extension after the config fetch.

Location
chrome.storage.local fetched config settings
Contents
{  "routeChance": 100,  "routeUseFrames": false,  "popupInPageVendorBlocklist": [    "amazon",    "walmart",    "target",    "ebay",    "etsy"  ]}
The code that does this

Remote config fetch, daily alarm, and stored behavior controls

Readable version

Readable remote config class

deobfuscated/js/background.js
const o = "configLastFetched",  s = "config";class c {  constructor() {    this.config = i, this.init()  }  static getInstance() {    return c.instance || (c.instance = new c), c.instance  }  async init() {    const {      config: e    } = await chrome.storage.local.get(s);    e && (this.config = e)  }  getConfig() {    return this.config  }  async fetchRemoteConfig() {    const {      configLastFetched: e    } = await chrome.storage.local.get(o);    if (e && Date.now() - e < 18e5) return this.config;    try {      const e = await fetch("https://cdn.share-a-cart.com/config.json");      if (!e.ok) throw new Error(`Failed to fetch remote config: ${e.statusText}`);      const t = await e.json();      return this.config = r()(this.config, t), await chrome.storage.local.set({        [o]: Date.now(),        [s]: this.config      }), this.config    } catch (e) {      const t = e instanceof Error ? e.message : String(e);      throw new Error(`Failed to fetch remote config: ${t}`)    }  }}

Readable daily alarm and storage writes

deobfuscated/js/background.js
chrome.alarms.onAlarm.addListener(({  name: e}) => {  if (l.info(`Waking up for alarm: ${e}`), "fetchConfig" === e) {    t.TS.getInstance().fetchRemoteConfig().then(t => {      try {        t.routeChance >= 0 && t.routeChance <= 100 && chrome.storage.local.set({          routeChance: t.routeChance        });        const {          routeUseFrames: e        } = t;        chrome.storage.local.set({          routeUseFrames: e        });        const {          popupInPageVendorBlocklist: n        } = t;        Array.isArray(n) && chrome.storage.local.set({          popupInPageVendorBlocklist: n        })      } catch (t) {        l.errorToSentry(`[alarm: ${e}] error`, t, {          tags: {            type: "alarm"          }        })      }    }).catch(() => {});    try {      fetch(`${t.TS.getInstance().getConfig().dbEndpoint}/aws~health-check`, {        method: "GET",        mode: "no-cors",        cache: "no-store"      }).then(async e => {        e.ok && "OK" === await e.text() ? u() : u(!0)      }).catch(() => {        u(!0)      })    } catch (e) {      u(!0)    }  }}), chrome.alarms.create("fetchConfig", {  periodInMinutes: 1440,  when: Date.now()})

Readable use of the stored popup blocklist

deobfuscated/js/background.js
chrome.tabs.onUpdated.addListener(async (e, t, {  active: n,  url: a}) => {  "complete" === t.status && n && a && (Hn.refresh(a), Promise.all([chrome.storage.local.get("popupInPageVendorBlocklist"), chrome.storage.sync.get("popup")]).then(([{    popupInPageVendorBlocklist: t  }, {    popup: n  }]) => {    if ("false" === n) return;    if (Yn && Yn.indexOf("Firefox") >= 0) return;    const r = Bn.B.getInstance().getVendorByURL(a),      i = t || Xn.popupInPageVendorBlocklist;    r && e && -1 === i.indexOf(r.id) && chrome.scripting.executeScript({      files: ["js/popup.js"],      target: {        tabId: e      }    })  }))})
Remote host contacted for configuration
    • cdn.share-a-cart.com

    Serves the JSON configuration file that can update routing and popup-control settings.

Cart-Sharing Beacon Now Fires For 290 Vendors, Not Just 2

The extension sent a GET to share-a-cart.com with the site's hostname within seconds of a Sam's Club cart.

The gate flipped from an allow-list (Sam's Club/Shein) to a deny-list (Amazon/Target), so ~290 of 292 adapters can now trigger it.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-200
Source
Dynamic sandbox
What actually happens
You did this

You create a cart on one of the extension's 290 non-Amazon, non-Target retail vendors.

The relevant path is the same create-cart message handler documented for Sam's Club and Shein.

The extension did this

The extension sends that vendor's hostname to share-a-cart.com, rate-limited to once per vendor per day.

The vendor gate that used to allow only two vendors now excludes only Amazon and Target.

The code that does this

The vendor gate flipped from allow-list to deny-list in the latest version.

Readable version

Readable allow-list version (previous shipped version)

deobfuscated/js/background.js
performRedirectorFetch(e, t) {  if (["samsclub", "shein"].includes(e.id)) try {    const {      hostname: n    } = new URL(t), a = this.lastFetchMap.get(e.id) || -1, r = Date.now();    if (-1 === a || r > a + 864e5) {      this.lastFetchMap.set(e.id, r);      const t = `https://share-a-cart.com/u/${encodeURIComponent(`https://${n}`)}`;      fetch(t, {        mode: "no-cors"      }).catch(() => {})    }  } catch (e) {}}

Readable deny-list version (current shipped version)

deobfuscated/js/background.js
performRedirectorFetch(e, t) {  if ((0, i.U)() !== i.u.SAC) return;  if (["amazon", "target"].includes(e.id)) return;  const n = r.TS.getInstance().getConfig();  try {    const {      hostname: a    } = new URL(t), r = this.lastFetchMap.get(e.id) || -1, i = Date.now();    if (-1 === r || i > r + 864e5) {      this.lastFetchMap.set(e.id, i);      const t = `${n.site}/u/${encodeURIComponent(`https://${a}`)}`;      fetch(t, {        mode: "no-cors"      }).catch(() => {})    }  } catch (e) {}}
Fields placed in the Share-A-Cart request URL
  • Shopping-site hostname
    https://www.samsclub.com

    Lets Share-A-Cart know which shopping site you were using when the cart was created.

  • Vendor bucket
    samsclub

    Identifies which bundled vendor you were using; only Amazon and Target are excluded from sending this field.

Captured request
GEThttps://share-a-cart.com/u/https%3A%2F%2Fwww.samsclub.com

Observed during dynamic analysis: the background service worker issued this request within seconds of clicking the extension's cart-creation control on a Sam's Club product page. No-cors requests are opaque, so no response status or body is available to the extension.

Destination host
    • share-a-cart.com

    Receives the shopping-site hostname for any bundled vendor other than Amazon or Target.

+1 more finding not shown

Updated 30 September 2026hcjohblbkdgcoikaedjndgbcgcfoojmj