Is WASender Free Bulk Messaging Plugin safe?
Send bulk WhatsApp messages to multiple contacts without saving each number first.
This extension lets users add contacts manually or upload an Excel sheet, then type and send WhatsApp messages in bulk. The store description says Pro features add personalized messages, attachments, batching and time-gap controls, contact download, filtering, and message reports.
Who publishes itwasender-main-devs - no other listings under this identity, 3 shared hostnames
wasender-main-devs - no other listings under this identity, 3 shared hostnames
What this publisher told the store about itself, and the other listings that told it the same thing.
Shared hosts - 3 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.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Account setup details are posted to TeleCRM
First-time setup collects your WhatsApp name, phone, email, country, and account phone into CRM lead records.
The source posts to a TeleCRM endpoint and an AWS Gateway endpoint, each with an embedded auth value.
No live POST was captured.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-200
- Source
- Dynamic sandbox
You submit the account setup form after entering your name, WhatsApp number, and email address.
The first-signup path runs after the extension saves those details.
The extension creates a CRM lead from those account details and prepares POST requests with embedded authorization values.
The source contains both a TeleCRM route and an AWS API Gateway CRM route for lead creation.
- Your account nameAman Gupta
This identifies the person or business account using the extension.
- Your signup phone number+91 8873520027
This is the WhatsApp number you enter during setup, including country information.
- Your email addressaman.gupta@example.in
This can identify and contact you outside the extension.
- Your country selectionIndia / IN / +91
This adds location context to the account record sent during setup.
- Your extension account phone+91 9027172291
This links the CRM lead to the phone number already associated with the extension account.
- Embedded CRM authorizationBearer <redacted>
The request includes a bundled authorization value rather than prompting you to approve a separate CRM connection.
No live response was captured; the POST URL and method are reconstructed from the shipped service-worker source.
- Content-Type
- application/json
- Authorization
- Bearer <redacted>
No live response was captured; the POST URL and method are reconstructed from the shipped main bundle source.
- Content-Type
- application/json
- Authorization
- AdminBearer <redacted>
The first-signup path and CRM POST helpers
First-time signup calls lead creation
deobfuscated/969.jshandleFirstTimeSignup() { var e = this; return (0, l.Z)(function*() { try { yield e.log.getCookies(), e.log.createLead({ fields: e.log.getCookies(), actiontexts: ["Signup done", JSON.stringify(e.log.getCookies(), null, 2)] }) } catch (o) { console.error("Error in creating lead", o) } try { e.extDataService.getAuth()?.isPro() || (yield e.userService.activateFreePlan(), setTimeout(() => { e.uiService.refresh() }, 0)) } catch (o) { console.error("Error in activating free plan", o) } })()}Log wrapper copies extension account details into leadService.createLead
deobfuscated/main.jscreateLead(pt) { var it = this; return (0, h.Z)(function*() { const lt = it.extAuth.currentUser.phoneNumber, It = it.extAuth.currentUser.name, Ut = it.extAuth.getUserDetails()?.email, Ot = it.extAuth.getUserDetails()?.countryInfo, xn = it.extAuth.getUserDetails()?.number; return it.leadService.createLead({ name: It, phoneNumber: xn, email: Ut, countryInfo: Ot, alternatePhone: lt }) })()}Lead service builds the CRM entity and POSTs to AWS API Gateway
deobfuscated/main.jscreateLead(pt) { return (0, h.Z)(function*() { const it = [{ fieldId: "contact_name", type: "TEXT", valueText: pt.name }, { fieldId: "contact_phone", type: "PHONE", valuePhone: { countryInfo: pt.countryInfo || { name: "India", code: "IN", dial_code: "91" }, phoneNumber: pt.phoneNumber } }, { fieldId: "contact_status", type: "DROPDOWN", valueDropdown: "New lead" }, { fieldId: "contact_source", type: "DROPDOWN", valueDropdown: "WACA" }]; pt.email && it.push({ fieldId: "contact_email", type: "EMAIL", valueEmail: pt.email }), pt.alternatePhone && it.push({ fieldId: "1_TEXT", type: "TEXT", valueText: pt.alternatePhone }); const lt = { id: "", eId: H, entityType: "CONTACT", fields: it, parentEntityId: "", parentEntityType: null, activities: [], createdBy: "", lastSeenTimestamp: 0, creationTimestamp: Date.now(), modificationTimestamp: Date.now() }; try { const It = yield fetch(`https://6vokqgdnu4.execute-api.ap-south-1.amazonaws.com/enterprise/${H}/entities`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: "AdminBearer <redacted>" }, body: JSON.stringify({ entity: lt }) }); if (!It.ok) { const Ot = yield It.json(); throw new Error(`HTTP ${It.status}: ${Ot.message||"Unknown error"}`) } return yield It.json() } catch (It) { console.error("Error creating contact:", It) } })()}Service worker POSTs lead properties to TeleCRM
deobfuscated/service-worker.jsstatic createLead(e) { var a = this; return o(function*() { return a.httpPost(`${y_CRM_ROUTE}`, e, { Authorization: "Bearer <redacted>" }) })()}Message route exposes the service-worker lead creation call
deobfuscated/service-worker.jscase t.API_CREATE_LEAD: return g.createLead(i.data.properties).then(n => a(n)).catch(n => { console.error("Error in API_CREATE_LEAD:", n), a(null) }), !0- next-api.telecrm.in
TeleCRM endpoint used by the service worker to receive lead properties from the extension.
- 6vokqgdnu4.execute-api.ap-south-1.amazonaws.com
AWS API Gateway endpoint used by the main bundle to create CRM contact entities.
Configured campaign cookies are added to analytics events
After an authenticated session on WhatsApp Web, the extension reads wasender.com cookies (origin, clickid, campaignid) as Amplitude properties sent to its cloud endpoint.
Logged-out POSTs show empty properties; authentication was untested.
- Severity
- Low unwanted
- Type
- Unexpected
- CWE
- CWE-522
- Source
- Dynamic sandbox
You open the extension while a WhatsApp Web session is available.
The cookie collection path runs during the extension refresh after it loads account and app configuration data.
The extension reads configured wasender.com cookie names and stores any returned values as analytics properties.
Later Amplitude events include those properties in the userProperties object sent to the cloud function.
- Campaign origin cookieorigin=google (illustrative)
This can connect your extension activity to a campaign or referral source if the cookie is present.
- Click attribution cookieclickid=CjwKCAjwq7fABhB2EiwAwk-Yb9mE2 (illustrative)
This can tie your extension session to a specific advertising or referral click if the cookie is present.
- Campaign ID cookiecampaignid=summer_launch_2026 (illustrative)
This can add campaign context to analytics events associated with your extension session.
Dynamic analysis observed logged-out analytics posts with empty userProperties.
{eventType:logged_out,userId:null,userProperties:{}}Cookie values are merged into Amplitude userProperties
Default and remotely configurable cookie names
main.jsconstructor(b, H, ee, De, be, $e = Q.BUY_FRAME_DEFAULT_URL, Xe = !1, Ht = 10, pt, it, lt) { this.DEFAULT_COOKIES = ["origin", "clickid", "campaignid"], this.reviewMode = !1, this.freeMessageLimit = 10, this.waSenderCookies = this.DEFAULT_COOKIES, this.suggestBan = b, this.banner = H, this.bannerIframeLink = ee, this.helpNumber = De, this.buyFrameLink = $e, this.reviewMode = Xe, this.freeMessageLimit = Ht, this.waSenderCookies = pt, this.autoRenewalLink = it, this.manageRenewalLink = lt, this.onBoardingFrameURL = be}static fromJSON(b) { let H = null; return b && (H = new Q({}, {}, "", "", "", Q.BUY_FRAME_DEFAULT_URL, !1, 10, [], "", ""), H.suggestBan = b.suggestBan ? b.suggestBan : {}, H.banner = b.banner ? b.banner : {}, H.bannerIframeLink = b.bannerIframeLink ? b.bannerIframeLink : "", H.helpNumber = b.helpNumber ? b.helpNumber : "", H.buyFrameLink = b.buyFrameLink ? b.buyFrameLink : Q.BUY_FRAME_DEFAULT_URL, H.reviewMode = !!b.reviewMode && b.reviewMode, H.freeMessageLimit = b.freeMessageLimit ? b.freeMessageLimit : 10, H.waSenderCookies = b.waSenderCookies ? b.waSenderCookies : H.DEFAULT_COOKIES, H.autoRenewalLink = b.autoRenewalLink ? b.autoRenewalLink : "", H.manageRenewalLink = b.manageRenewalLink ? b.manageRenewalLink : "", H.onBoardingFrameURL = b.onBoardingFrameURL ? b.onBoardingFrameURL : ""), H}Cookie source URL constant
main.jsconst q = { APP_SERVER_ROUTER: "https://wasender.ai/api/b1", APP_SERVER: "http://wasender.ai/api", CLIENT_URL: "https://wasender.com", SAFE_AND_MONTERING: "6558718ad99bc6ef5c706a94", NEW_CUSTOMER: "6284dde8d771c4000970f6bc", TEMPLATE_ID_SAFE_AND_MONTERING: "6558718ad99bc6ef5c706a97", TEMPLATE_ID_NEW_CUSTOMER: "64c2a9c678aa832f68e69a2f", BAN_PREVENT_LINK: "https://wasender.ai/banning-tips-ai?send=true", ROOT_LAMBDA_URL: "http://localhost:3000", ROOT_URL: "https://us-central1-waplugin-34798.cloudfunctions.net", DATA_S3: "https://wasender-data.s3.ap-south-1.amazonaws.com", INDEX_DB_NAME: "wanew", CRM_ROUTE: "https://next-api.telecrm.in/enterprise/60a51c74589084cee99c1903/autoupdatelead", ROOT_LAMBDA_URL: "https://3fsfla67nmbaykipymj7qlsahy0uymzo.lambda-url.ap-south-1.on.aws", SELECTOR_URL: "https://us-central1-waplugin-34798.cloudfunctions.net/stats/adds", SUPPORT_NUMBER: "919528066739", chatSyncBatchSize: 50}Chrome cookie read helper
main.jsgetCookie(be, $e) { return new Promise((Xe, Ht) => { chrome.cookies.get({ url: be, name: $e }, pt => { chrome.runtime.lastError ? (console.error(chrome.runtime.lastError), Ht(chrome.runtime.lastError)) : Xe({ value: pt?.value, name: $e }) }) })}Configured cookies copied into analytics properties
main.jsgetWaSenderCookie() { var x = this; return (0, Q.Z)(function*() { try { const de = wt.N.CLIENT_URL, We = x.extDataService.appConfig.waSenderCookies.map(Kt => x.waService.getCookie(de, Kt)), Ke = yield Promise.all(We), ft = {}; Ke.forEach(Kt => { Kt?.value && (ft[Kt.name] = Kt.value) }), x.log.setUniversalUserProperties(ft) } catch (K) { console.error("Error in getting cookies", K) } })()}Universal properties included in log payload
main.jssetUniversalUserProperties(pt) { Xe.UNIVERSAL_USER_PROPERTIES = { ...Xe.UNIVERSAL_USER_PROPERTIES, ...pt }}log(pt, it = {}, lt = {}) { var It = this; return (0, h.Z)(function*() { const Ut = It.extAuth.currentUser.phoneNumber, Ot = k.nB.getManifestData(), wt = { ...Object.fromEntries(Object.entries(it).map(([Mt, Rt]) => [Mt, String(Rt)])), version: String(Ot?.version), isPro: String(It.extAuth.isPro()) }, Nt = { extUserName: String(It.extAuth.currentUser.name), extPhoneNumber: String(It.extAuth.currentUser.phoneNumber), phoneNumber: It.extAuth.getUserDetails()?.number, signupNumber: `${It.extAuth.getUserDetails()?.countryInfo?.dial_code}${It.extAuth.getUserDetails()?.number}`, email: It.extAuth.getUserDetails()?.email, name: It.extAuth.getUserDetails()?.name, countryCode: It.extAuth.getUserDetails()?.countryInfo?.name, getTips: String(It.extAuth.getUserDetails()?.getTips), installTimestamp: String(It.extAuth.getUserDetails()?.installTimestamp), verifiedEmail: String(It.extAuth.getUserDetails()?.verifiedEmail), isPro: String(It.extAuth.isPro()), ...Xe.UNIVERSAL_USER_PROPERTIES }; yield k.bl.logAmplitude(pt, Ut, wt, Nt) })()}Service worker POST to cloud function
service-worker.jsstatic logAmplitude(e, a, r, n) { var E = this; return o(function*() { const m = `${y_ROOT_URL}/stats/log-amplitude`; yield E.httpPost(m, { eventType: e, userId: a, eventProperties: r, userProperties: n }, { Authorization: `Bearer ${a}`, Version: E.getVersion() }) })()}- us-central1-waplugin-34798.cloudfunctions.net
Receives Amplitude event payloads from the extension, including the userProperties object populated by the cookie-reading code path.