Is Pragmaz for WhatsApp™ Web safe?
Pragmaz for Whatsapp strips WhatsApp Web's security headers network-wide and routes its traffic through a shared proxy password.
The extension ships network rules that remove Content-Security-Policy, Permissions-Policy and CORS headers on whatsapp.com/whatsapp.net traffic and rewrite the Origin/Referer headers to web.whatsapp.com, and these rules are not limited to requests started by web.whatsapp.com itself. It also hardcodes a Bright Data residential-proxy password, shared by every install, used to route WhatsApp Web traffic through zproxy.lum-superproxy.io. Separately, it redirects WhatsApp's own integrity-check manifest to a fixed old version and blocks WhatsApp's killswitch and crash-log endpoints, which are the mechanisms WhatsApp Web uses to detect tampering by extensions like this one.
Who publishes itpragmaz - no other listings under this identity, 1 shared hostname
pragmaz - no other listings under this identity, 1 shared hostname
What this publisher told the store about itself, and the other listings that told it the same thing.
Shared hosts - 1 hostname
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
Hardcoded Bright Data proxy password is identical in every install
The extension answers Chrome's proxy login prompt for zproxy.lum-superproxy.io with a password hardcoded in the shipped code, identical in every install.
Anyone who downloads the extension can read the password out of the file.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-522
- Source
- Dynamic sandbox
You use the extension's proxy feature to route WhatsApp Web traffic through a chosen region.
Chrome needs login credentials to authenticate to that upstream proxy.
The extension answers Chrome's proxy login prompt with a password that is a literal string in the shipped code, the same in every install.
The username and password together authenticate directly to the vendor's Bright Data proxy zone.
- Proxy passwordxo5ofp3byw6r
A fixed password value that is identical in every copy of the extension.
- Proxy username prefixbrd-customer-hl_c2a52987-zone-data_center-ip-us
Combined with a region code, this authenticates as the vendor's Bright Data customer account.
- Proxy endpointsession-3f7ac1.zproxy.lum-superproxy.io:22225
The upstream proxy address the credential unlocks.
Proxy authentication handler in the shipped extension
Same handler; the file already ships with readable names, no minification to reverse
js/service-worker.js:9-19var auth_now = function (details, callbackFn) { if (details.isProxy && localStorage['proxy']) { callbackFn({ authCredentials: { username: 'brd-customer-hl_c2a52987-zone-data_center-ip-' + localStorage['proxy'], password: 'xo5ofp3byw6r' } }); }};Reads the extension's background script and recovers the hardcoded Bright Data proxy username prefix and password.
- Node.js 18+
const fs = require('fs');const path = process.argv[2];if (!path) { console.error('usage: node extract-proxy-credential.js <path-to-service-worker.js>'); process.exit(1);}const src = fs.readFileSync(path, 'utf8');const userMatch = src.match(/username:\s*'([^']+)'/);const passMatch = src.match(/password:\s*'([^']+)'/);if (!userMatch || !passMatch) { console.error('No proxy credential literals found in this file.'); process.exit(1);}console.log('Proxy username prefix:', userMatch[1]);console.log('Proxy password:', passMatch[1]);- 1Unzip the extension's CRX.
- 2Run node extract-proxy-credential.js path/to/service-worker.js.
- 3The script prints the recovered username prefix and password.
- zproxy.lum-superproxy.io
Bright Data (Luminati) proxy endpoint authenticated to with the hardcoded credential.
- lumtest.com
Bright Data's own IP-check endpoint, also routed through the same proxy zone.
Shipped rules block WhatsApp Web's own tamper-check endpoints
On web.whatsapp.com, shipped rules block requests to WhatsApp's own killswitch, update-check and crash-log URLs, and pin its integrity manifest to an older version.
The same URLs via fetch or XHR were not blocked.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-506
- Source
- Dynamic sandbox
You open web.whatsapp.com with the extension enabled.
The extension's content scripts and injected CSS load into the page starting at document start.
Shipped rules block full-page and script-tag requests to WhatsApp's killswitch, service-worker and check-update URLs, and redirect its integrity manifest to a fixed older version.
We confirmed the block for a direct navigation and a script-tag load; the same URLs loaded via fetch from the page were not blocked.
- Killswitch checkweb.whatsapp.com/killswitch -> blocked (main_frame, script)
WhatsApp's own remote switch for disabling clients it flags as tampered.
- Service worker fileweb.whatsapp.com/serviceworker.js -> blocked (main_frame, script)
WhatsApp's own service worker; part of how it verifies the running client.
- Update checkweb.whatsapp.com/check-update -> blocked (main_frame, script)
WhatsApp's endpoint for checking whether the loaded client is current.
- Crash telemetrycrashlogs.whatsapp.net/* -> blocked (main_frame, script)
WhatsApp's own crash reports, which could otherwise surface interference from injected code.
- Integrity manifestbinary-transparency-manifest*.json -> redirected to -2.2407.2.json
WhatsApp's manifest for verifying the code it served, pinned to an old version instead of the current one.
The direct navigation and a script-tag load both failed with net::ERR_BLOCKED_BY_CLIENT. A fetch() request to the same URL from the live tab returned a normal HTTP response instead of being blocked.
The killswitch and check-update blocks above were confirmed live. The binary-transparency manifest redirect and the crashlogs.whatsapp.net block (rules 9 and 13) were not independently re-tested live and are confirmed by rules.json alone.
Parses the extension's declarativeNetRequest ruleset and lists every WhatsApp URL it blocks or redirects.
- Node.js 18+
const fs = require('fs');const path = process.argv[2];if (!path) { console.error('usage: node list-blocked-whatsapp-endpoints.js <path-to-rules.json>'); process.exit(1);}const rules = JSON.parse(fs.readFileSync(path, 'utf8'));for (const rule of rules) { const filter = rule.condition && rule.condition.urlFilter; if (!filter || !filter.includes('whatsapp')) continue; const action = rule.action || {}; if (action.type === 'block') { console.log(`id ${rule.id}: BLOCK ${filter} (resourceTypes: ${(rule.condition.resourceTypes || []).join(', ')})`); } else if (action.type === 'redirect') { const target = action.redirect && (action.redirect.url || action.redirect.regexSubstitution); console.log(`id ${rule.id}: REDIRECT ${filter} -> ${target}`); }}- 1Unzip the extension's CRX.
- 2Run node list-blocked-whatsapp-endpoints.js path/to/rules.json.
- 3The script prints every WhatsApp URL the ruleset blocks or redirects.
Where it sends data
Destinations our analysis observed WhatsUp+ contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.
- web.whatsapp.com
WhatsUp+ sends data to web.whatsapp.com. 10 other extensions we have analyzed send data here.
- zproxy.lum-superproxy.io
WhatsUp+ sends data to zproxy.lum-superproxy.io. One other extension we have analyzed sends data here.