Is North Ad-Block safe?
North Ad-Block transmits open-tab domains to its server on install and allows that server to push arbitrary JavaScript into every browsed page.
On installation, the extension collects the hostnames of all open browser tabs and sends them to api.n-adb.com, then continues forwarding per-site ad-block counts and tab domains every 60 seconds. The server can respond with inline JavaScript code that the extension injects and executes in the main world of each page the user visits, giving the server full access to page content, credentials, and session data. A separate message handler in the content script accepts storage writes from any web page without validating the origin, which can allow a malicious site to overwrite authentication tokens used by the extension.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
The vendor server can run arbitrary JavaScript on every site you visit
This ad blocker periodically checks in with api.n-adb.com.
A reply header x-fetch-scriptlets triggers a rules download whose lines run as raw JavaScript in the page (MAIN world), with the site's own script access.
DA confirmed it.
What actually happens
The vendor server replies to a routine check-in with a header that points to a rules file.
The x-fetch-scriptlets header on the /heartbeat response tells the extension to download /rules/scriptlets.txt.
On your next page load, JavaScript from that file runs inside the page with the same access the website's own scripts have.
Lines marked with #%# are stored as inline code and executed in the page's MAIN world.
The code that does this
Server-supplied lines are parsed as JavaScript, then executed in the page
The chain, in plain terms
// 1. Routine /heartbeat reply includes x-fetch-scriptlets.// 2. Extension downloads /rules/scriptlets.txt from the same server.// 3. Any line like example.com#%#<JS> is stored as runnable code for example.com.// 4. When you open example.com, the extension runs <JS> in the page's// MAIN world via new Function(<JS>) - same access as the page's own scripts.// 5. The content script is granted <all_urls>, so this works on any site.Reproduce it yourself
Shows the exact storage shape the extension produces from a server-supplied scriptlets.txt line, and the line of server text that produces it. Confirms a single server-controlled line becomes JavaScript that runs in the page.
// A single line in /rules/scriptlets.txt served by api.n-adb.com:const serverLine = "example.com#%#window.__marker='ran'; document.title='changed';";// transformScriptletTextToObject() turns that line into this storage entry:const storedRule = { "scriplet_example.com": [ { code: "window.__marker='ran'; document.title='changed';", isOnlyForMainFrame: false, type: "inline" } ]};// On navigation to example.com, adBlocking.js executes, in the page's MAIN world:// new Function(storedRule['scriplet_example.com'][0].code)()// i.e. the server-supplied string runs as page JavaScript.console.log(JSON.stringify(storedRule, null, 2));- 1Run: node scriptlets-rule-shape.js.
- 2Compare output to the shape from transformScriptletTextToObject() in rulesManager.js.
- 3The 'code' value runs via new Function() in the page's MAIN world by executeScriptletInjections().
Why MAIN-world execution matters
Code run in the MAIN world shares the page's JavaScript context. It can read and modify anything the website's own scripts can: page content, form inputs, and the logged-in session for whatever site you are on. Because the content script is granted access to all URLs, the same mechanism applies to every site you visit, and the code that runs is chosen by the server at request time rather than fixed in the published extension.
Domains of every open tab sent to api.n-adb.com the moment you install
On install, this ad blocker reads every open tab's domain (e.g. chatgpt.com, x.com) and sends that list in its first request to api.n-adb.com.
DA confirmed both domains were stored, then transmitted, a snapshot an ad blocker doesn't need.
What actually happens
You install the ad blocker while other tabs are already open.
The extension reads the domain of every open tab and sends that list to its vendor server.
It runs chrome.tabs.query({}) on the install event, skips chrome:// and extension pages, and keeps the unique domain of every other tab.
The code that does this
The install handler collects open-tab domains and includes them in the first server request
What it does, in plain terms
// 1. On install, list every open tab.// 2. Throw away chrome:// and extension URLs.// 3. Reduce each remaining URL to its domain (chatgpt.com, x.com).// 4. Save that list, then POST it to https://api.n-adb.com/initialize// inside the initialTabDomains field of the first request body.Captured request
Observed during dynamic analysis with chatgpt.com and x.com open at install time. The server returned 204 and the same initialTabDomains list was retained for later requests.
- Content-Type
- application/json
{ "blockedCounts": {}, "initialTabDomains": [ "chatgpt.com", "x.com" ]}What the install request reveals about you
- Domains of your open tabs["chatgpt.com", "x.com"]
The website of every tab you had open when you installed the ad blocker, captured as a one-time snapshot of what you were doing.
Open-tab domains and per-site block counts sent to api.n-adb.com on a timer
Beyond the install report, this ad blocker posts to api.n-adb.com/heartbeat roughly every 60 seconds, an interval the server can change.
The payload has install-time tab domains plus a per-site count of blocked ads.
What actually happens
A repeating alarm fires roughly once a minute.
configureSynchronizationAlarm sets the period; the server can change it via x-heartbeat-interval.
The extension sends your install-time tab domains and per-site block counts to its vendor server.
buildTelemetryPayload assembles the report and POSTs it to api.n-adb.com/heartbeat.
When this fires
Every 1 minute
A synchronization alarm POSTs a telemetry payload to api.n-adb.com/heartbeat about every 60 seconds. The interval defaults to 60s and is overridden by the x-heartbeat-interval header the server returns, so the vendor controls how often reporting happens.
Captured request
Observed during dynamic analysis: repeated POSTs to api.n-adb.com/heartbeat over the session, each carrying initialTabDomains and a blockedCounts map. The response may set x-heartbeat-interval to re-time future reports.
- Content-Type
- application/json
- Authorization
- Bearer <redacted>
{ "blockedCounts": {}, "initialTabDomains": [ "chatgpt.com", "x.com" ]}What each heartbeat reports
- Install-time tab domains["chatgpt.com", "x.com"]
The domains of the tabs you had open when the extension was installed, re-sent on every heartbeat.
- Per-site block counts{"nytimes.com": 14, "youtube.com": 7}
How many ad requests were blocked on each site. Because counts only accrue on sites you open, this map reveals which sites you visit.
What it can do
Permissions this extension asks for, as declared in version 1.0.22. Asking for a permission is not a finding on its own - it is what the extension can do if it chooses to.
Read and change your data on every site you visit
<all_urls>
Schedule its own background tasks
alarms
Block and redirect the requests your browser makes
declarativeNetRequest
Run its own code inside the pages you visit
scripting
Store data in your browser
storage
See the address and title of every tab you have open
tabs
Store an unlimited amount of data in your browser
unlimitedStorage
See every page you navigate to, as you navigate to it
webNavigation
Where it sends data
Destinations our analysis observed North Ad-Block contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.
- api.n-adb.com
North Ad-Block sends data to api.n-adb.com. No other extension we have analyzed sends data here.
