Is Privacy Extension For WhatsApp Web - wabulk.net safe?

Medium risk

Privacy for WhatsApp Web is medium risk. Once WhatsApp Web loads, the worker requests ad placements from ext.leadsext.com, using the install token from registration. A placement triggers a promo and view/click reports, timezone included. This session captured only the fetch.…

smallduckv3.3.19Chrome Web Store
45Risk

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

Publishers can request a review.

Findings

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

New promo-tracking channel reports your engagement to leadsext.com

Once WhatsApp Web loads, the worker requests ad placements from ext.leadsext.com, using the install token from registration.

A placement triggers a promo and view/click reports, timezone included.

This session captured only the fetch.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You open WhatsApp Web and your session finishes loading.

The extension did this

The background service worker automatically fetches promo placements from ext.leadsext.com and wires up reporting for anything it renders in the page.

The request carries the persistent session token issued when the extension was first installed, so the fetch is tied to your specific installation.

02EvidenceNETWORK CAPTURE
Captured request
POSThttps://ext.leadsext.com/crx/rtio
200 OK. Body is gzip+base64 encoded JSON that decodes to {"placements":{},"message":"success"}, no placements were returned in this test, so no promo card rendered and no follow-up engagement report fired.
Headers
crx_vcwgjg<redacted session token>
Content-Typeapplication/json
Body
{}
03EvidenceCODE COMPARE
The code that does this

Placement fetch and engagement-report function, both via the same router and fetch wrapper

What it actually does
getPromotions — the function that fired live during dynamic analysisassets/chunk-7da65e19.js
const getPromotions = async () => {
  try {
    const result = await (async (cachedPlacementIds = []) => {
      const response = await fetchWithSessionToken("https://ext.leadsext.com/crx/rtio", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: cachedPlacementIds.length > 0 ? { placements: cachedPlacementIds } : {}
      });
      if (200 === response.code) {
        let payload = response.result;
        if (typeof payload === "string") {
          const decompressed = gzipHelper.ungzip(payload);
          payload = decompressed ? JSON.parse(decompressed) : { placements: {} };
        }
        return payload || { placements: {} };
      }
      throw new Error(response.message || "getPromotions failed");
    })();
    extensionState.setPromoPlacements(result.placements || {});
  } catch (e) {}
};
reportPromotionAction — wired to PROMO_VIEWED/CLICKED/CLOSED, not independently captured on the wire this sessionassets/chunk-7da65e19.js
const reportPromotionAction = async ({ promotionId, displaySessionId, userAction, viewDurationMs }) => {
  const reportPayload = {
    promotionId,
    displaySessionId,
    userAction,
    ...(viewDurationMs !== undefined && { viewDurationMs }),
    userTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
    userLocalTime: (new Date()).toISOString()
  };
  const response = await fetchWithSessionToken("https://ext.leadsext.com/crx/wewfu", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: { data: gzipHelper.gzipToBase64(JSON.stringify(reportPayload)), rtl: "" }
  });
  if (200 === response.code) {
    let result = response.result;
    if (typeof result === "string") result = gzipHelper.ungzip(result) || result;
    return result;
  }
  throw new Error(response.message || "reportPromotionAction failed");
};
04EvidenceFIELD TABLE
Fields in the engagement report; code path present, not captured on the wire
FieldValueWhy it matters
How long you viewed the promo
viewDurationMs: 4213The time between the promo appearing and you dismissing or clicking it.
Your local timezone
userTimezone: "America/Sao_Paulo"Read from your browser's Intl settings, this narrows down your general location.
What you did with the promo
userAction: "click"Whether you viewed, clicked, or closed the promotional content.
Your install session token
crx_vcwgjg header (redacted)The same permanent token used to identify your installation on every other request this extension makes.
05EvidenceTHIRD PARTY LIST
Where placement fetches and engagement reports go
  • ext.leadsext.com

    Extension analytics/promo backend, same host as the install-registration channel; serves placements via /crx/rtio, receives engagement reports via /crx/wewfu.

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-829
SourceAI SANDBOX

Remote config from ext.leadsext.com controls DOM selectors and feature flags

On each start, the extension fetches gzip config from ext.leadsext.com/crx/cjj2: 9,400+ chars of JSON stored as dockingInfo.

It sets which DOM selectors target WhatsApp Web, which CSS injects, and which banners show, remotely, no update.

01EvidenceNETWORK CAPTURE
Captured request
GEThttps://ext.leadsext.com/crx/cjj2?aid=749905846386-8ntjrq2jnhhh8cjuq3qgro3d67i2sj1q.apps.googleusercontent.com&v=3.3.16&l=en-GB&unicode=3027aaadacba46d3b6c116bf3be7871f&timestamp=1780679526814&aidd=749905846386-8ntjrq2jnhhh8cjuq3qgro3d67i2sj1q.apps.googleusercontent.com&idUni=wa-privacy
Headers
crx_vcwgjg<session-token-from-registration>
02EvidenceSTORAGE DUMP
What's stored on your device

inStor/notLInStor are the selectors the MutationObserver watches; gc/pc set how many ratings trigger a prompt.

Location
Contents (JSON)
{
  "dockingInfo": {
    "gc": 1,
    "pc": 1,
    "pss": {},
    "email": "support@wabulk.net",
    "inStor": "div._1jJ70",
    "webUrl": "https://wabulk.net/",
    "helpUrl": "https://privacy-wa-web.wabulk.net/help",
    "notLInStor": "div.x1lliihq canvas",
    "toolsRedDot": 0
  }
}
03EvidenceCODE COMPARE
Unknown block kind: code_compare

The data has shipped a block kind this view doesn't render yet. Raw payload below.

{
  "kind": "code_compare",
  "language": "js",
  "shipped": [],
  "deobfuscated": []
}
04EvidenceTHIRD PARTY LIST
Third-party destinations
  • ext.leadsext.com

    Remote configuration server, delivers feature flags, DOM selectors, CSS rules, and promotional content to all active installations.

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

Persistent anonymous identifier sent to ext.leadsext.com on install

On install, the extension generates a UUID stored in chrome.storage.sync.

A POST to ext.leadsext.com/crx/in carries that UUID and an OAuth client ID.

The server replies with token crx_vcwgjg, attached to later requests, linking reinstalls.

01EvidenceNETWORK CAPTURE
Captured request
POSThttps://ext.leadsext.com/crx/in
Headers
Content-Typeapplication/x-www-form-urlencoded
Body
aid=749905846386-8ntjrq2jnhhh8cjuq3qgro3d67i2sj1q.apps.googleusercontent.com&idStr=wa-privacy&anonCode=ec95b3f05f0a4ad297312c69cf699c97&unicode=3027aaadacba46d3b6c116bf3be7871f&timestamp=1780679526814&aiid=749905846386-8ntjrq2jnhhh8cjuq3qgro3d67i2sj1q.apps.googleusercontent.com&idUni=wa-privacy&aCode=ec95b3f05f0a4ad297312c69cf699c97
02EvidenceCODE COMPARE
Unknown block kind: code_compare

The data has shipped a block kind this view doesn't render yet. Raw payload below.

{
  "kind": "code_compare",
  "language": "js",
  "shipped": [],
  "deobfuscated": []
}
03EvidenceSTORAGE DUMP
What's stored on your device

Stored in chrome.storage.sync, the key follows the user's Chrome account and resends on any device with the extension.

Location
Contents (JSON)
{
  "Y5rD2uBG_ANON_CODE": "ec95b3f05f0a4ad297312c69cf699c97"
}
04EvidenceTHIRD PARTY LIST
Third-party destinations
  • ext.leadsext.com

    Extension analytics and session management backend, receives install events, anonymous UUIDs, and Google OAuth client ID; issues persistent session tokens.

Updated 21 September 2026mbcghjiodcjankhkllfohcgnckhdbkmi