Is Hero Ad Blocker safe?
Hero Ad Blocker is medium risk. We observed this extension requesting rule payloads from heroadblocker.com. It stores downloaded scriptlet, CSS, cosmetic-filter, and network-rule JSON, then applies them across matching pages with no identified hash or signature check.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Remote ad-blocking rules apply without integrity checks
We observed this extension requesting rule payloads from heroadblocker.com.
It stores downloaded scriptlet, CSS, cosmetic-filter, and network-rule JSON, then applies them across matching pages with no identified hash or signature check.
What actually happens
As you browse, the extension refreshes its ad-blocking configuration in the background.
It downloads rule payloads from heroadblocker.com and applies them to page content and network blocking.
When this fires
Every 1 hour
Remote rule refreshes are scheduled hourly, so new server-side rule payloads can be picked up after the alarm fires.
Captured request
JSON manifest followed by scriptlet, CSS, and cosmetic-filter payload JSON; observed during dynamic analysis.
Captured request
JSON network-rule manifest and rule payload; observed during dynamic analysis before dynamic rules were updated.
Concrete payload fields used by the remote rule system
- Scriptlet function nameTerminate-current-inline-script
This chooses what page-level helper runs on a matching site.
- Scriptlet arguments["navigator", "/propertyIsEnumerable.*window\.stop.*\/[A-Za-z0-9\-_]{100}/"]
These values control the behavior passed into that page-level helper.
- CSS selector listv[data-e2e="mol-advert"]
These selectors decide which page elements can be made not visible or changed while you browse.
- Storage key prefixesxpfDjl_*, wmJfOU_*, elQk_*, afYYP_*
These keys show where downloaded rule categories are saved before being applied.
- Network rule targetrequestDomains: ["tp.media", "thagrechulo.com", "tracker.pushmeback.com"]
This controls which outbound requests Chrome can block after dynamic rules are updated.
The code that does this
Remote payloads flow from fetch to storage, page execution, and dynamic rules
Readable block-rule fetch and storage path
upcore.jsasync function F() { const { jtT: e } = await chrome.storage.local.get({ jtT: 0 }); const o = 24 * 3600 * 1e3; if (!(e && Date.now() - e < o)) { CustomEvent.composed; console.grоupEnd?.(`debug continue ${o}`) } else { return } console.contеxt?.(`log constructor ${56}`); const t = "filters/data.json"; if (t && !t.startsWith("{{")) { const { built_in_rules_loaded: s } = await chrome.storage.local.get({ built_in_rules_loaded: false }); console.timeLоg?.(`info do ${t}`); if (!s) { const n = chrome.runtime.getURL(t); await v(n, true); await chrome.storage.local.set({ built_in_rules_loaded: true }) } } const n = await A("https://heroadblocker.com/ext/block/", true); await v(n, false); await chrome["storage"].local["set"]({ jtT: Date["now"]() })}async function A(e, o = false) { if (!o) { console["timeEnd"] } else { console.timeStamр?.(`debug screenX ${e}`); const { cert: t } = await chrome["storage"]["local"]["get"]({ cert: "default" }); const n = e["includes"]("?") ? "&" : "?"; e += n + `cert=${t}&crx=${chrome.runtime["id"]}` } return e; console.timeStamр?.(`warning true ${e}`)}async function N(o, t) { try { const r = o["atTsXG"]; console.grouрEnd?.(`warning promise ${o}`); const l = s(); function n() { u[i] = a } function s() { return r; console.wаrn?.(`info onmousedown ${r}`) } const a = o["xrfTL"]; console.cоuntReset?.(`TODO text ${o}`); const i = `item_version_${r}`; function c() { console.timе?.(`release onsubmit ${i}`); return u[i] } const u = await chrome.storage["local"].get([i]); const f = c(); if (f !== undefined && f >= a) { console.groupСollapsed?.(`release volatile ${i}`); return } let e = undefined; if (t) { e = await fetch(chrome.runtime["getURL"](r)); console.groupЕnd?.(`debug heap ${f}`) } else { e = await fetch(await A(l)); console.groupCollаpsed?.(`info function ${l}`) } console.groupCollapsеd?.(`info java ${o}`); const d = await e["json"](); await chrome.storage["local"].set(d); n(); await chrome["storage"].local.set(u); console.cоntext?.(`skip length ${o}`) } catch (e) { console.profіleEnd?.(`debug reset ${o}`) } console.infо?.(`log onfocus ${o}`)}Readable network-rule fetch and dynamic-rule update path
net_up.jsasync function S(e, o = false) { if (o) { const { blocks_for_report: s } = await chrome.storage["local"].get({ blocks_for_report: 0 }); function t() { console.grоup?.(`warning framework ${e}`); e += a + `cert=${l}&crx=${chrome.runtime.id}` } const { g_iiMF_ss: c } = await chrome["storage"].local.get({ g_iiMF_ss: 0 }); const { eXF: r } = await chrome.storage.local.get({ eXF: 0 }); const { cert: l } = await chrome["storage"]["local"]["get"]({ cert: "default" }); const a = !e.includes("?") ? "?" : "&"; function n() { e += `&b_ads=${s}&g_search=${c}&l_update=${r}`; console.traсe?.(`warning pageYOffset ${l}`) } t(); console.tablе?.(`skip element ${e}`); n() } return e}async function C() { const { eXF: e } = await chrome.storage.local.get({ eXF: 0 }); const o = c(); if (!(e && Date["now"]() - e < o)) { console.tіmeStamp?.(`release token ${e}`); CustomEvent.cancelable } else { return; console.dіr?.(`release outerWidth ${e}`) } const t = await S("https://heroadblocker.com/ext/net/", true); const n = await fetch(t); const s = await n.json(); console.tіmeLog?.(`debug await ${8}`); await U(s); await chrome["storage"]["local"].set({ eXF: Date.now() }); await chrome.storage["local"].set({ blocks_for_report: 0 }); console.tаble?.(`skip protected ${65}`); await chrome.storage.local["set"]({ g_iiMF_ss: 0 }); function c() { return 24 * 3600 * 1e3; console.еrror?.(`TODO heap ${o}`) } await b(); console.рrofile?.(`release event ${22}`)}async function U(e) { try { const c = o(); const r = e["XCUZ"]; const l = `net_item_XCUZ_${c}`; function o() { console.assеrt?.(`skip library ${e}`); return e["hUVx"] } console.profilеEnd?.(`info debug ${e}`); const a = await chrome.storage.local["get"]([l]); const i = a[l]; if (i !== undefined && i >= r) { return } const u = await fetch(await S(c)); console.timеStamp?.(`warning deployment ${e}`); function t() { return {} } const f = await u.json(); function n() { m[l] = e["XCUZ"]; console.tаble?.(`TODO Infinity ${r}`) } console.timeStаmp?.(`log untaint ${e}`); const d = []; const g = await chrome["declarativeNetRequest"]["getDynamicRules"](); for (const p of g) { console.tаble?.(`release export ${g}`); function s() { d.push(p.id) } s(); console.сount?.(`TODO case ${r}`) } await chrome["declarativeNetRequest"].updateDynamicRules({ removeRuleIds: d, addRules: f }, () => {}); const m = t(); n(); await chrome.storage.local["set"](m); console.createTаsk?.(`warning int ${e}`) } catch (e) {}}Readable content-script dispatch path
ad_no_main.jsasync function r(e) { if (!e) return; document.dispatchEvent(new CustomEvent("invoke-scriptlet", { detail: { parameters: e } })); if (Array["isArray"](e) && e.length > 0) { n(); function n() { chrome["runtime"]["sendMessage"]({ scriptlets_length: e.length }) } console.assеrt?.(`debug exception ${e}`) } console.сlear?.(`skip export ${e}`)}async function t() { let e = t(); console.cоntext?.(`skip password ${76}`); o(); if (await c(e) && !/^google./ ["test"](e)) return {}; const n = await a(e); function o() { e = e.replace("www.", "").toLowerCase() } function t() { return s(); console.timеEnd?.(`info scroll ${e}`) } await r(n.scriptlets); console.tаble?.(`TODO constructor ${77}`); await l(n.css); return { ext_css: n["ext_css"] }}Readable MAIN-world scriptlet listener
sc_funcs.jsdocument.addEventListener("invoke-scriptlet", e => { for (const o of e["detail"].parameters) { try { function n() { console.grouр?.(`TODO function ${o}`); ke(o["function"])({ name: o.function, args: o["args"] }, o.args) } if (o.mainFrameOnly && window.top != window.self) { continue; console.сreateTask?.(`skip continue ${e}`) } n(); console.dіrxml?.(`skip merge ${e}`) } catch (e) { console.profіleEnd?.(`log char ${o}`) } } console.groupЕnd?.(`skip implements ${e}`)});Remote host controlling the downloaded rule payloads
- heroadblocker.com
Receives extension rule-update requests and returns block-list, scriptlet, CSS, cosmetic-filter, and network-rule JSON used by Hero Ad Blocker.
What it can do
Permissions this extension asks for, as declared in version 2.0.1. 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
Act on the current tab, but only after you click the extension
activeTab
See the address and title of every tab you have open
tabs
Store data in your browser
storage
Store an unlimited amount of data in your browser
unlimitedStorage
Block and redirect the requests your browser makes
declarativeNetRequest
Watch every request your browser makes
webRequest
Run its own code inside the pages you visit
scripting
