Is Rocket Sender - Bulk WA Messages & Automation safe?
Rocket Sender automates WhatsApp messaging and decides where to activate from a class-name list fetched from its remote config server.
The background script downloads a configuration file from cdn2.waplus.io and stores it locally; the content script (declared on all sites) injects the privileged WhatsApp automation bundle wherever a page matches the remotely supplied CSS class list, so the vendor can change the targeted sites by editing remote config. Background telemetry posts the user's logged-in WhatsApp phone number, a derived country code, install UUID, install time and browser details to an Alibaba Cloud logstore on tracked events. When a user shares a link in WhatsApp, the inject script also forwards the full shared URL to one of three third-party link-preview servers to generate the preview.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
WhatsApp link previews send shared URLs to preview servers
When you send a WhatsApp message with a link, Rocket Sender replaces the preview generator, sending the full URL to one of three servers: cobrancas.uppermesh.com.br, wajsapi.titanchat.com.br, wppc-linkpreview.cloudtrix.com.br.
You compose or send a WhatsApp message that includes a link.
The preview path is reached only when WhatsApp Web can generate a link preview inside an active chat.
The extension builds a preview request that includes the full link.
The link is appended as the `url` query parameter before the request is sent to a configured preview server.
| Field | Value | Why it matters | |
|---|---|---|---|
Shared link | https://example.com/secret-path (illustrative test URL from the verification recipe) | This can reveal the exact page, document, invite, or other destination you are sending in a WhatsApp chat. | |
Request parameter | url=https://example.com/secret-path (illustrative test URL from the verification recipe) | The link is sent in the address bar of the preview request rather than kept only inside WhatsApp Web. | |
Preview destination | wajsapi.titanchat.com.br | A server selected by the extension receives the shared link so it can return preview metadata. |
The shipped code wraps WhatsApp's preview generator and builds the preview-server URL
u.onFullReady((() => {
(0, l.wrapModuleFunction)(d.getABPropConfigValue, ((e, ...t) => {
const [r] = t;
return "link_preview_wait_time" === r ? 7 : e(...t)
})), (0, l.wrapModuleFunction)(d.genMinimalLinkPreview, (async (e, ...t) => {
const [r] = t, n = "string" == typeof r ? r : r.url;
return new Promise((async r => {
try {
const e = await (0, c.fetchRemoteLinkPreviewData)(n);
if (!e) throw new Error(`preview not found for ${n}`);
const {
imageUrl: t
} = e, o = s(e, ["imageUrl"]);
let i = {};
t && (i = await (0, c.generateThumbnailLinkPreviewData)(t).catch((() => null))), r({
url: n,
data: Object.assign(Object.assign({}, o), i)
})
} catch (n) {
r(await e(...t))
}
}))
}))
}))t.fetchRemoteLinkPreviewData = async function(e) {
if (p[e]) return l("Link preview found in the cache", e), p[e];
const t = new TextDecoder;
for (let r = d.length - 1; r >= 0; r--) {
const n = d[r];
l(`Fetching link preview using ${n}`, e);
const o = `${n}/v1/link-preview/fetch-data.png?url=` + encodeURI(e),
i = await (0, c.fetchDataFromPNG)(o).then((e => t.decode(e))).then((e => JSON.parse(e))).catch((() => null));
if (null === i || !("title" in i) && !("status" in i)) {
l(`The server ${n} is unavailable for link preview`), d.splice(r, 1);
continue
}
if (!i.title && 200 !== i.status) continue;
const a = /^video/.test(i.mediaType),
s = {
title: i.title,
description: i.description,
canonicalUrl: i.url,
matchedText: e,
richPreviewType: a ? 1 : 0,
doNotPlayInline: !a,
imageUrl: i.image
};
return p[e] = s, setTimeout((() => {
delete p[e]
}), 3e5), s
}
return null
};
const d = i.config.linkPreviewApiServers || ["https://cobrancas.uppermesh.com.br:8000", "https://wajsapi.titanchat.com.br", "https://wppc-linkpreview.cloudtrix.com.br"];
! function(e) {
for (let t = e.length - 1; t > 0; t--) {
const r = Math.floor(Math.random() * (t + 1));
[e[t], e[r]] = [e[r], e[t]]
}
}(d)t.fetchDataFromPNG = function(e) {
return new Promise(((t, r) => {
const n = new Image;
n.crossOrigin = "anonymous", n.src = e, n.onerror = r, n.onload = function() {
const e = document.createElement("canvas"),
r = e.getContext("2d");
e.width = n.naturalWidth, e.height = n.naturalHeight, r.drawImage(n, 0, 0);
const o = r.getImageData(0, 0, e.width, e.height).data,
i = new Uint8Array(Math.floor(3 * o.length / 4));
for (let t = 0, n = 0; t < o.length; t += 4) i[n++] = o[t], i[n++] = o[t + 1], i[n++] = o[t + 2];
let a = BigInt(0);
for (let t = 0; t < 8; t++) a = (a << BigInt(8)) + BigInt(i[t]);
const s = Number(a);
t(i.subarray(8, 8 + s))
}
}))
}- cobrancas.uppermesh.com.br
Fallback preview API server from the shipped server list; the code appends `/v1/link-preview/fetch-data.png?url=` and the shared link.
- wajsapi.titanchat.com.br
Fallback preview API server from the shipped server list; the code appends `/v1/link-preview/fetch-data.png?url=` and the shared link.
- wppc-linkpreview.cloudtrix.com.br
Fallback preview API server from the shipped server list; the code appends `/v1/link-preview/fetch-data.png?url=` and the shared link.
Remote config picks which sites get the WhatsApp automation bundle
Rocket Sender's content script runs on every site, checking CSS class names from cdn2.waplus.io (refreshed every 5 min); a matching class injects bundle inject.js.
This activates only on web.whatsapp.com today; the gate is remote config.
You open a website in your browser.
The content script is registered on <all_urls>, so it runs on the page regardless of which site it is.
The extension checks the page against a class-name list it downloaded from the developer's server, and injects its automation bundle if the page matches.
The list is fetched from cdn2.waplus.io and refreshed every five minutes, so the developer controls which pages activate the automation.
The content script gates injection on a remotely supplied class list
async function maybeInject() {
if (alreadyInjected) return;
const { zbaseConfig } = await chrome.storage.local.get(["zbaseConfig"]);
const { class_list } = zbaseConfig?.data?.config
?.find(e => e.name === "WAPI Class")?.params || [];
for (const cssClass of class_list) {
if (document.querySelector(`.${cssClass}`)) { // page DOM matches a remote class
alreadyInjected = true;
await injectScript("/inject.js", "inject"); // add privileged bundle to the page
window.localStorage.setItem("rocketSender", true);
await startAutomation();
break;
}
}
if (!alreadyInjected) setTimeout(maybeInject, 2000); // re-poll the DOM
}
function injectScript(path, id) {
return new Promise((resolve, reject) => {
const s = document.createElement("script");
s.id = id;
s.src = chrome.runtime.getURL(path); // inject.js from the extension bundle
s.onload = resolve; s.onerror = reject;
document.head.appendChild(s);
});
}The background service worker fetches and caches the remote class list
function refreshConfig() {
chrome.storage.local.get(["zbaseConfig", "configLastFetchTime"], (cached) => {
const now = Date.now();
const TTL = 300000; // 5 minutes
const stale = !cached.zbaseConfig || !cached.configLastFetchTime
|| now - cached.configLastFetchTime > TTL;
if (stale) {
fetch("https://cdn2.waplus.io/extensiton/rocket-sender/config/config.json",
{ cache: "no-store" })
.then(r => r.json())
.then(cfg => chrome.storage.local.set({
zbaseConfig: cfg,
configLastFetchTime: now,
}));
}
});
}| Cache-Control | no-store |
The background service worker re-fetches the remote class list whenever the cached copy is older than five minutes, so the set of pages that activate the automation can change roughly every five minutes without an extension update.
During dynamic analysis the background request to cdn2.waplus.io returned the class list, and inject.js was injected only on web.whatsapp.com, whose DOM contains those classes. After navigating to example.com and Wikipedia (which contain none of the listed classes), no further injection occurred. This confirms the activation is controlled by the remote class list rather than the <all_urls> manifest pattern. The injected code (inject.js) ships inside the extension and depends on WhatsApp Web internals, so the remote config controls targeting, not the code body.