Is Dropship - Product Research safe?

High risk

Dropship.io is high risk. Dropship - Product Research requests your Google account ID on install, stores it locally, and sends it to the Dropship API. A GET to users/rating was captured with the user token header set; the token is also on the app client.…

Dropship.iov2.4.6Chrome Web Store
75Risk
Who publishes it

Dropship FZCO - 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.

Publisher
Dropship.io
Declared legal entity
Dropship FZCO
Registered contact
Nawras Nashwan Ganim Ganim

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.

api.dropship.io
Also called by 1 other listing: ShopifyHunt - Shopify™ Spy Tool & AliExpress™ Product Research

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

Publishers can request a review.

Findings

Google account ID reused as Dropship API token

Dropship - Product Research requests your Google account ID on install, stores it locally, and sends it to the Dropship API.

A GET to users/rating was captured with the user token header set; the token is also on the app client.

Severity
High unwanted
Type
Unexpected
CWE
CWE-359
Source
Dynamic sandbox
What actually happens
You did this

You install the Dropship extension.

The extension did this

The extension requests your Google account identifier, saves it as a local token, and attaches it to Dropship API requests.

Captured request
GEThttps://api-ws-extension.prod.dropship.io/api/users/rating/

A request to this endpoint was observed within the first 10 seconds after extension load.

Headers
Extension-Token
sdfkljsbdfgoipoasji2318743460r9edlfgjhpre896544534854368tfd34lfgkjbpfgepofdgsoidfsopdfjspodfjsidfjgphjmweorwjeoir5487623423jkdflgdkf874538953459834
Extension-User-Token
107890220540720092498
Account-linked values used by the extension API
  • Your Google account identifier
    107890220540720092498

    This is a stable account-derived value, so requests carrying it can be tied back to the same Google profile over time.

  • Extension API token
    sdfkljsbdfgoipoasji2318743460r9edlfgjhpre896544534854368tfd34lfgkjbpfgepofdgsoidfsopdfjspodfjsidfjgphjmweorwjeoir5487623423jkdflgdkf874538953459834

    This fixed extension token identifies the client making the request and is sent alongside your account-derived token.

  • Dropship API host
    api-ws-extension.prod.dropship.io

    This is the remote service that receives the request containing the account-derived token.

What's stored on your device

The extension keeps the account-derived identifier locally and can reuse it after the first install-time lookup.

Location
chrome.storage.local key 'token'
Contents
{  "token": "107890220540720092498"}
The code that does this

Where the account identifier becomes a request header

Readable version

Install-time token creation and rating request

app/background.js
chrome.storage.local.get(null, async function(e) {  if (e.token) s = e.token;  else {    if (navigator.userAgent.includes("OPR")) s = R();    else {      let e = chrome.identity.getProfileUserInfo({        accountStatus: "ANY"      });      await (e?.then(e => {        s = e?.id ? e?.id : R()      }))    }    chrome.storage.local.set({      token: s    }), chrome.storage.local.set({      adBlocker: !1    }), fetch(`${r}users/rating/`, {      headers: {        "Content-Type": "application/json",        "Extension-Token": a,        "Extension-User-Token": s      },      method: "GET"    }).then(e => e.json()).then(e => {      chrome.storage.local.set({        rating: e?.rating || 0      }), chrome.runtime.sendMessage({        message: "getRateInner",        rating: e?.rating || 0      })    }).catch(() => chrome.storage.local.set({      rating: 0    })).finally(() => chrome.storage.local.set({      rating: 0    }))  }});

App API client reusing the stored token

static/js/main.js
function e() {  return en(this, e), this.baseURL = "https://api.dropship.io/api", e.instance || (this.create(), this.createInterceptor(), e.instance = this), e.instance}return nn(e, [{  key: "create",  value: function() {    var e = f(u.a.mark((function e() {      var t, n, r = this;      return u.a.wrap((function(e) {        for (;;) switch (e.prev = e.next) {          case 0:            return this.api = Jr.a.create({              baseURL: this.baseURL,              headers: {                "Content-Type": "application/json"              },              cancelToken: new Xr.CancelToken((function(e) {                r.source = e              })),              timeout: 6e4            }), e.next = 3, new Promise((function(e) {              chrome.storage.local.get("token", (function(t) {                e(t)              }))            }));          case 3:            t = e.sent, (n = t.token) && this.api.setHeader("Extension-User-Token", n), this.api.setHeader("Extension-Token", "sdfkljsbdfgoipoasji2318743460r9edlfgjhpre896544534854368tfd34lfgkjbpfgepofdgsoidfsopdfjspodfjsidfjgphjmweorwjeoir5487623423jkdflgdkf874538953459834");          case 7:          case "end":            return e.stop()        }      }), e, this)    })));    return function() {      return e.apply(this, arguments)    }  }()}, {  key: "cancelAllRequest",  value: function() {    e.instance.source()  }}, {  key: "createInterceptor",  value: function() {    this.interceptors = this.api.axiosInstance.interceptors  }}]), e}

Navigation triggers a Shopify metadata request

Browsing to a site makes Dropship - Product Research check its origin via /meta.json.

We saw it request shop.tesla.com/meta.json after navigating there; the background code uses that response to decide if the site is a Shopify store.

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

You navigate to a website in a browser tab.

The confirmed test navigation was to https://shop.tesla.com.

The extension did this

The extension requests that site's /meta.json file to check for Shopify metadata.

If the response reports published products, the extension records the tab's origin and Shopify domain for later UI updates.

Captured request
GEThttps://shop.tesla.com/meta.json

Observed after navigating to https://shop.tesla.com; the claim evidence did not record a request body for this GET request.

Concrete fields used by the metadata check
  • Visited site origin
    https://shop.tesla.com

    Shows which website you opened so the extension can decide whether that site is a Shopify store.

  • Metadata URL
    https://shop.tesla.com/meta.json

    Adds a predictable Shopify metadata path to the site you visited and requests it automatically.

  • Published product count
    published_products_count: 42

    Lets the extension decide whether to treat the current site as a Shopify store with products.

  • Shopify store domain
    myshopify_domain: tesla-shop.myshopify.com

    Lets the extension associate the browser tab with a Shopify store domain after the metadata response is parsed.

The code that does this

The navigation listener builds the /meta.json request from the active tab origin

Readable version

Fetch helper in the deobfuscated bundle

deobfuscated/app/background.js
async function x(e) {  return !o.some(t => e.includes(t)) && await fetch(`${e}/meta.json`).then(e => e.json()).catch(() => !1)}

Navigation listener in the deobfuscated bundle

deobfuscated/app/background.js
chrome.tabs.onUpdated.addListener(async function(e, {  status: t}) {  let n, [r] = await chrome.tabs.query({      active: !0,      currentWindow: !0    }),    a = r?.url ? new URL(r?.url)?.pathname : "",    s = a?.includes("admin"),    i = await U();  if (i?.id && (V(i), r?.url && ("complete" === t || "loading" !== t) && !s)) {    if (n = new URL(r?.url).origin, o.some(e => n.includes(e)) || l.some(e => e?.id === r?.id)) return;    if (f.some(e => e?.id === r?.id && e?.url === n)) return;    let t = await x(n);    t?.published_products_count ? (f.some(e => e?.id === r?.id) && (f = [...f.filter(t => t?.id !== e)]), l.some(e => e?.id === r?.id) || l.push({      id: r?.id,      url: n,      myshopify_domain: t?.myshopify_domain    })) : (chrome.tabs.sendMessage(r.id, {      message: "hide_extension"    }), f.some(e => e?.id === r?.id) ? f.some(e => e?.id === r?.id) && (f = f.map(e => e?.id === r?.id ? {      id: r?.id,      url: n    } : {      ...e    })) : f.push({      id: r?.id,      url: n    }))  }})
Hosts observed or constructed for metadata checks
    • shop.tesla.com

    Received the observed /meta.json GET request after navigation to that origin.

    • www.dropship.io

    Also appeared in the verification evidence as a /meta.json probe during the same analysis.

Updated 30 September 2026pgccoaecgcgnhffkjjcaonjoockggmng