Wonder Ad Blocker: Reverse Engineering a Malicious Chrome Extension
A Chrome extension marketed as an ad blocker — with 500,000+ users — was operating as a distributed ad-intelligence scraping platform. Reverse engineering revealed tracking-script injection, browsing-data harvesting, and command infrastructure phone-home.
I was pirating a movie. I’m not going to pretend there’s a noble origin story here. I was on one of those sites, a popup appeared trying to get me to install a Chrome extension called “Ad Block Wonder,” and instead of closing it like a normal person, I thought: I wonder what this thing actually does.
It had 500k users. 4+ stars on the Chrome Web Store. The listing calls it “the successor to uBlock”, which is a wild claim to make about an extension distributed through piracy site popups, but sure. I pulled the source code and started reading.
I did not expect to spend the next several hours mapping out a six-platform ad intelligence scraping operation.
”Barely 2000 lines of code”
We’ll get to why that quote matters in a minute, but let’s start with what’s actually in this extension.
The first thing you notice is a directory called src/blocker/special/scripts/. Inside are six files: facebook.js, x.js, reddit.js, tiktok.js, pinterest.js, twitch.js. Each one is a dedicated scraping module for its respective platform. These aren’t blockers at all, they’re collectors. They hook into browser APIs to intercept API responses in real time and extract ad data from them.
facebook.js is 2,206 lines. Just that one file. For an extension that “barely” has 2,000 lines total. The full codebase across JS/CSS/JSON is over 1.7 million lines.
But I’m getting ahead of myself.
Your browsing history, on a schedule
Before we even get to the fun platform-specific stuff, let’s talk about what the extension does on every single page you visit.
A content script called broker.js runs on every URL, at document_start, in all frames. Every time you navigate to a top-level page, it logs the domain and increments a counter. Visit Reddit 47 times this week? It knows. These get stored as navDoms: a neat little dictionary of your browsing habits with frequency counts.
When you first install the extension, a function called installDataGathering() runs and snapshots every tab you currently have open. All those domains go into installDoms. So, from the moment of installation, the extension knows what you were doing.
Both of these — your ongoing browsing history and your install-time snapshot — get POSTed as plaintext JSON to the developer’s server. In v3.8 that was wonderadblock.com/wonder-3_7.php. In v4.1 it moved to wonderupdates.com/wonder-3_7.php. More on that domain switch later.
The payload also includes a persistent user ID (stored as wonderinformation — incredible variable name), your extension version, your personal allowlist, and as of v4.1, three shiny new tracking parameters: sid, cid, and an. Those are affiliate/campaign attribution tags scraped from the Chrome Web Store URL at install time. They tell the developer which ad network or shady popup drove your install, so they can pay their distribution partners accordingly.
No encryption on any of this by the way. The HTTP helper is a bare fetch() with Content-Type: application/json and JSON.stringify(body). Just plaintext JSON over HTTPS. They didn’t even try.
Facebook: 2,206 lines of “not a Facebook script”
facebook.js is where things get genuinely impressive, in a “wow, someone put real engineering effort into this grift” kind of way.
The file starts with hardcoded lookup tables for parsing personal data. Relationship statuses, like Single, In a Relationship, Married, Engaged, Civil Union, Domestic Partnership, Open Relationship, It’s Complicated, Separated, Divorced, Widowed. Education levels from “In high school” through “Doctorate degree.” These are for categorizing you.
The main event is WAIST scraping — WAIST being Facebook’s “Why Am I Seeing This” transparency feature. When you click that on an ad, Facebook shows you what targeting criteria the advertiser used to reach you. This extension scrapes all of it automatically for every ad it encounters. The targeting categories it extracts include:
Age and gender. Relationship status. Education level and schools. Employer and job title. Interests. Location. Locale. And the really fun ones — Custom Audiences from datafiles (advertiser-uploaded customer lists), Custom Audiences from website pixel tracking, Custom Audiences from mobile app activity, and Lookalike audiences. Over 30 targeting categories total.
There’s a whole ParseWAIST module that resolves Facebook’s internal Relay GraphQL fragments and packages the targeting data with the advertiser’s ID, name, and profile picture into a clean object. Someone sat down and reverse engineered Facebook’s internal ad transparency UI to build this. That’s not trivial work.
But it gets better. There’s a function called getAccessToken() (which, just by the way, incredible naming decision if you’re trying to claim this extension is innocent). It navigates to adsmanager.facebook.com/adsmanager/ inside your authenticated session, scrapes the __accessToken (a 100+ character Facebook Graph API token), the token’s expiry time, and your c_user cookie (your Facebook user ID). These get stored in an IndexedDB database named mooz.
The extension then uses your stolen token to make authenticated Graph API calls for advertiser fanpage data, like contact info, email, phone numbers, business hours, Instagram account, follower counts. This is happening silently in the background while you browse Facebook thinking your ads are being blocked. Whether it’s also sent to the developer’s server I can’t confirm from static analysis, but it’s being harvested and stored persistently either way.
And to make all of this work, the extension injects a declarativeNetRequest rule (ID 9999992, because of course it’s a magic number) that overrides Facebook’s own CORS security headers. It sets Access-Control-Allow-Credentials to true and Access-Control-Allow-Origin to facebook.com on all Facebook responses. Facebook’s security team put those headers there for a reason. This extension removes them.
The same pattern, five more times
The same hook-intercept-exfiltrate pattern repeats across X/Twitter, Reddit, TikTok, Pinterest, and Twitch. Each module hooks XMLHttpRequest or fetch prototypes to intercept API responses, filters for ad content, and extracts targeting and engagement data. The technique varies slightly per platform, but the structure is identical. Intercept the API response before the page sees it, extract the ad data, send it home. (Side note: the handler that would relay it to the server isn’t obviously wired up in these versions, but everything is there for it to do so.)
Twitch is worth calling out separately because it crosses a line the others don’t. The fetch hook captures your Authorization header, Client-Integrity token, Client-ID, and Device-ID from intercepted GQL requests, then uses those credentials to make its own authenticated requests on your behalf. It also overrides document.visibilityState and document.hidden, tricking the site into thinking you’re actively watching when you’re not. This is, pretty cleanly, credential harvesting.
The fake stats
My favorite detail. When you click the extension popup, it shows you stats about how much data the extension has “saved” you and how much faster your pages are loading. Confidence-inspiring numbers with units and everything.
They’re completely made up.
randomBetweenTwoNumbers(400, 600) for the timing. randomBetweenTwoNumbers(30, 60) for the kilobytes. Literally Math.random(). The stats in the popup are generated fresh every time you look at them with no relation to anything that actually happened. Pure theatre for user retention.
I genuinely respect the audacity.
The remote control
When the extension phones home, the server sends instructions back. The response can include:
wondercycle, which controls how often the extension phones homerules, an array ofdeclarativeNetRequestrules that gets applied viaupdateDnrRules(), which replaces all existing dynamic rules with whatever the server sendswhitelistedDomainsandallowedDomains, domains that bypass all blocking entirelyscriptletExcludes, domains excluded from scriptlet injection
The developer has full remote control over what gets blocked and what doesn’t across 500k browsers. That rules array can include redirect rules, not just block/allow. The mechanism to silently redirect URLs through the extension is sitting right there.
The developer responds
I posted a review detailing the browsing history exfiltration and the existence of the platform scraping modules. The developer replied publicly:
I am genuinely speechless… I can only assume you’re mistaking my extension with another. There is no Facebook specific script… there is barely 2000 lines of code in the whole extension.
He then asked me to “be kind enough to correct your review.”
So I downloaded v4.1, the version he shipped after my review. I diffed it against v3.8.
facebook.js is byte-for-byte identical. Still 2,206 lines. Still imported at scripts.js:1. Still mapped to facebook.com in domains.js:2. Still scraping WAIST data. Still stealing Graph API tokens. The developer shipped a new version, replied publicly claiming the file doesn’t exist, and didn’t change a single byte of it.
What did change in v4.1:
- The server endpoint moved from
wonderadblock.comtowonderupdates.com. - Three new tracking parameters (
sid,cid,an) were added to the exfiltration payload. - The new tracking keys were mirrored to Chrome sync storage so they persist across reinstalls.
So after being publicly called out for data collection, the developer: denied everything, moved the server to a new domain, and added more tracking. I’ll let you sit with that for a minute.
The product itself
None of this code is obfuscated. Every variable name is plaintext: getAccessToken, sendAd, wonderinformation, navDoms, installDoms. The developer didn’t webpack it, didn’t minify it, didn’t run it through any kind of transform. They just shipped human-readable JavaScript that steals your Facebook access token in a function called getAccessToken and apparently assumed nobody would ever open the files and look.
For 500k installs and months on the Chrome Web Store, they were right. The Web Store review process didn’t flag any of it. The extension has a 4+ star rating. It’s still live as of this writing.
But I think the interesting question isn’t “how did this get through review.” It’s “what is this thing actually for.”
This isn’t adware in the traditional sense. The developer isn’t injecting banner ads into your pages or swapping out affiliate links. This is an ad intelligence platform. Someone is building a cross-platform dataset of ad creatives, targeting parameters, engagement metrics, and advertiser contact information — harvested from real user sessions on Facebook, X, Reddit, TikTok, Pinterest, and Twitch. Layered on top is per-user browsing history with visit frequency, tied to a persistent ID, with affiliate attribution tracking to map the install funnel.
That’s a product. Ad intelligence platforms, at least the legitimate ones, charge thousands per month for this kind of data. Who’s running ad campaigns on Facebook targeting women aged 25–34 in Dallas who work at Deloitte and are interested in yoga? What creative are they using? How much engagement is it getting? What’s the advertiser’s contact info? Normally you’d need to pay a SaaS company a lot of money for those answers. Or you could just contact “Ad Block Wonder” and let half a million people’s browsers collect it for you for free.
The browsing history adds a behavioral layer on top, because now you don’t solely have ad targeting data, you have it correlated with browsing patterns. The affiliate tracking adds a distribution layer — you know exactly which shady popup networks are driving installs, so you can scale the ones that work. The remote-controlled whitelist adds a second revenue stream, as ad networks can pay to get un-blocked across 500k browsers with no user visibility. The server-pushed DNR rules add a third: arbitrary redirect capability across every URL those 500k users visit.
This is the full stack of a shadow ad intelligence business, distributed through piracy site popups and disguised as an ad blocker. The only thing I can’t tell you from the code alone is who’s buying the data on the other end.
The extension is still live on the Chrome Web Store as of this writing. I’ve reported it to Google and the affected platforms’ security teams. If you have it installed, remove it.