Is Premium Sender Plus safe?

High risk

Premium Sender Plus is high risk. Premium Sender Plus's content script fetches selector JSON from premiumsenderplus.app on WhatsApp Web. The JSON has CSS selectors for chat titles, avatars, messages, media, and controls, used as config. The server can retarget elements.…

premiumsenderplusv1.1.79.53Chrome Web Store
77Risk

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

Publishers can request a review.

Findings

Server-controlled WhatsApp DOM selectors

Premium Sender Plus's content script fetches selector JSON from premiumsenderplus.app on WhatsApp Web.

The JSON has CSS selectors for chat titles, avatars, messages, media, and controls, used as config.

The server can retarget elements.

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

You open WhatsApp Web with Premium Sender Plus installed.

The extension did this

The extension retrieves a server-provided map of WhatsApp page selectors and uses it to target page elements.

The selector map is requested by the page bundle and fetched by the content script from premiumsenderplus.app.

Captured request
GEThttps://premiumsenderplus.app/mv3/dom-selectors-2.php

The endpoint returns JSON selector configuration; no request body is sent for this GET request.

Headers
Content-Type
application/json
Concrete selector fields returned by the remote endpoint
  • Main WhatsApp panel
    #main

    Tells the extension where the active WhatsApp conversation area is on your page.

  • Chat title selectors
    header ._ao3e, [data-testid='conversation-info-header-chat-title'], [data-testid='author'], [data-testid='chat-subtitle']

    Lets the configuration point features at the chat title shown in your WhatsApp conversation.

  • Message selectors
    message-in, .message-out, [data-testid='conversation-panel-messages'] [data-testid^='conv-msg']

    Lets the configuration identify incoming and outgoing message elements on your chat page.

  • Status media selectors
    [data-animate-status-viewer="true"] img[src^="blob"]

    Lets the configuration point download features at status images and videos displayed in WhatsApp Web.

  • Send control selectors
    [data-icon="send"],[data-icon="wds-ic-send-filled"]

    Lets the configuration identify the send button used by message automation features.

The code that does this

The page bundle requests selectors; the content script fetches them from the server

Readable version

Deobfuscated page bundle dispatches the selector request and stores the response

deobfuscated/page.min.js
(0, e.useEffect)((() => {  const e = "dom-".concat(Math.random());  a.once(e, (e => {    e && c(e)  })), window.dispatchEvent(new CustomEvent("pws::get-dom-selectors", {    detail: {      name: e    }  }))}), []), (0, e.useEffect)((() => {  AS.set({    dom_selectors: l  })}), [l])

Deobfuscated page bundle consumes server-supplied selectors in WhatsApp features

deobfuscated/page.min.js
e.blur_contact_names ? yw("blur_contact_names", rk(l.enhancements_mainchatclass_chattitle, l.enhancements_sidechatclass_chattitle)) : bw("blur_contact_names"), e.blur_contact_photos ? yw("blur_contact_photos", rk(l.enhancements_sidechatclass_chatavatar, l.enhancements_mainchatclass_chatavatar)) : bw("blur_contact_photos"), e.blur_recent_messages ? yw("blur_recent_messages", rk(l.enhancements_sidechatclass_chatsecondary)) : bw("blur_recent_messages"), e.blur_conversation_messages ? yw("blur_conversation_messages", rk(l.enhancements_messageclass_msg)) : bw("blur_conversation_messages"), e.pin_unread_chats ? (Pw(), window[ft].Chat.off("change:unreadCount", Pw), window[ft].Chat.on("change:unreadCount", Pw)) : (window[ft].Chat.where().filter((e => e.pin)).filter((e => window.pws_pinned_chats.includes(e.id.user))).map((e => e.pin = 0)), window.pws_pinned_chats = [], window[ft].Chat.off("change:unreadCount")), Nw(), window[ft].Chat.off("change:active"), window[ft].Chat.on("change:active", (() => Lw(e, n, l))), Lw(e, n, l)
Remote host involved in selector delivery
    • premiumsenderplus.app

    Receives the selector-configuration GET request and returns JSON used to target WhatsApp Web elements.

Install-time IP lookup sent to ip-api.com

We observed Premium Sender Plus make an install-time GET request to ip-api.com/json when it had no stored device name.

This lets ip-api.com infer your IP address; the extension uses the returned country code to set its default language.

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

You install the extension and first-run setup begins.

The extension did this

The extension contacts a geolocation service before choosing its default language.

Captured request
GEThttp://ip-api.com/json

Observed during dynamic analysis as an install-time GET request; the response contained a countryCode field.

Data involved in the geolocation lookup
  • Your IP address
    198.51.100.24 (illustrative)

    The remote geolocation service receives the network address your browser uses at install time.

  • Country code
    US

    The returned country code is used to choose the extension language.

  • Network provider
    ExampleNet, New York (illustrative)

    The service can return city and provider details associated with the connection.

The code that does this

Install handler that performs the geolocation lookup

Readable version

Readable install handler excerpt

deobfuscated/background.min.js
chrome.runtime.onInstalled.addListener(function() {  var t = s(o().mark((function t(e) {    var r, n;    return o().wrap((function(t) {      for (;;) switch (t.prev = t.next) {        case 0:          return t.next = 2, p({ device_name: "" });        case 2:          if (r = t.sent, "" !== r.device_name) {            t.next = 10;            break          }          return t.next = 7, Promise.all([fetch("http://ip-api.com/json").then((function(t) {            return t.json()          })), fetch("/countries.json").then((function(t) {            return t.json()          }))]).then((function(t) {            var e = c(t, 2), r = e[0], n = e[1];            if ("AE" === r.countryCode) return "en";            var i = n.find((function(t) { return t.alpha2 === r.countryCode }));            if (!i) return "en";            var o = (i.languages ? i.languages[0] : "en").split("_")[0];            return h[o] ? o : "en"          })).catch((function() { return "en" }));      }    }), t)  })));});
External host contacted by this claim
    • ip-api.com

    Receives the install-time geolocation lookup and returns country/location metadata.

License check posts phone and license details

Premium Sender Plus validates a license by combining the license key, device code, extension version, device name, and WhatsApp number, wrapping it with embedded AES constants, and posting it to premiumsenderplus.app/mv3/get-license-1.php.

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

You validate or reuse a Premium Sender Plus license.

The extension did this

The extension sends license, device, version, and WhatsApp number fields to its API.

Plaintext fields before the AES wrapper
  • License key
    PSP-8F42-2026-91AC (illustrative)

    This identifies the subscription credential being validated.

  • Device code
    B-1782148895331 (illustrative)

    This links the license check to a specific browser or device record.

  • Extension version
    1.1.79.46

    This tells the API which Premium Sender Plus build you are running.

  • Device name
    Chrome-Linux-Workstation (illustrative)

    This is the stored device name sent with the license check.

  • WhatsApp number
    +15551234567 (illustrative)

    This ties the license check to the WhatsApp account number loaded by the extension.

Captured request
POSThttps://premiumsenderplus.app/mv3/get-license-1.php

The source posts a FormData field named encData to this endpoint; no live request body was recorded in verification evidence.

The code that does this

License validation request and embedded AES constants

Readable version

Readable license request

deobfuscated/popup.min.js
sA = function() {  var e = t(a().mark((function e(n, t, i, r) {    var o, c, s, l, d;    return a().wrap((function(e) {      for (;;) switch (e.prev = e.next) {        case 0:          return o = chrome.runtime.getManifest().version, e.prev = 1, c = {            license_key: n,            device_code: t,            version: o,            device_name: i,            mobile: r          }, s = gA(JSON.stringify(c)), e.next = 6, nA("".concat(tA, "/get-license-1.php"), "POST", {            encData: s          });        case 6:          return l = e.sent, e.next = 9, hA(null == l ? void 0 : l.data);        case 9:          if (!(d = e.sent)) {            e.next = 12;            break          }          return e.abrupt("return", JSON.parse(d));      }    }), e, null, [[1, 14]])  })));  return function(a, n, t, i) { return e.apply(this, arguments) }}();

Readable request helper and AES helpers

deobfuscated/popup.min.js
nA = function() {  var e = t(a().mark((function e(n, t, i) {    var r, o, c, s;    return a().wrap((function(e) {      for (;;) switch (e.prev = e.next) {        case 0:          for (c in r = { method: t, redirect: "follow" }, o = new FormData, i) o.append(c, i[c]);          return r.body = o, "GET" === t && delete r.body, e.next = 7, fetch(n, r).then((function(e) { return e.json() }));        case 7:          return s = e.sent, e.abrupt("return", s);        case 9:        case "end":          return e.stop()      }    }), e)  })));  return function(a, n, t) { return e.apply(this, arguments) }}(),tA = "https://premiumsenderplus.app/mv3";mA = "abc123abc123abc123abc123abc123ab",pA = "a1b2c3d4e5f6g7h8",hA = function(e) {  if (e) {    var a = cL().enc.Utf8.parse(mA), n = cL().enc.Utf8.parse(pA);    return cL().AES.decrypt(e, a, { iv: n, padding: cL().pad.Pkcs7, mode: cL().mode.CBC }).toString(cL().enc.Utf8)  }},gA = function(e) {  if (e) {    var a = cL().enc.Utf8.parse(mA), n = cL().enc.Utf8.parse(pA);    return cL().AES.encrypt(e, a, { iv: n, padding: cL().pad.Pkcs7, mode: cL().mode.CBC }).toString()  }};
External host contacted by this claim
    • premiumsenderplus.app

    Receives the encrypted license-validation form field for the extension API.

+2 more findings not shown

Updated 30 September 2026cofbobkapfknpdllndaligcgmikmegbl