Is Focus & Productivity Booster safe?

Medium risk

Focus & Productivity Booster sends the title and hostname of every blocked page to safefocusing.com and fetches the list of sites it blocks from the same server.

When you visit a site on the extension's block lists (social media, streaming, user-added domains, and a remotely fetched list), it loads an iframe from safefocusing.com/safe/block.php with the page title and hostname appended to the URL. The set of blocked sites is pulled from safefocusing.com/filter/ at startup with no integrity check, and the extension strips X-Frame-Options and Referer headers for requests from safefocusing.com. A content-script message handler also runs fetch() with a URL and request options supplied by any message whose origin string merely contains 'safefocusing.com'.

49Risk

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

Publishers can request a review.

Findings

Framing and referrer headers removed for safefocusing.com

MediumunwantedCWE-940Dynamic sandbox

The extension installs a network rule for safefocusing.com main-frame, sub-frame, and XHR loads.

What actually happens

You did this

You install the extension and the background service worker starts.

The extension did this

The extension registers a browser network rule for requests initiated by safefocusing.com.

That rule removes one response header that blocks framing and one request header that identifies the referring page.

Concrete fields in session rule 1

  • Site that starts the request
    safefocusing.com

    Only requests started by this site match the rule, so the header changes are tied to that site rather than every site you visit.

  • Frame-blocking response header
    X-Frame-Options

    This header normally lets a site say it should not be embedded in another page. Removing it can change whether that page can be framed.

  • Referring-page request header
    Referer

    This header can show which page led to a request. Removing it strips that source-page context from matching requests.

  • Affected request types
    main frame, subframe, XMLHttpRequest

    The rule covers page loads, embedded frames, and background page requests initiated by the matching site.

The code that does this

The shipped bundle and readable source register the same header-removal rule

Readable version

Readable session-rule registration

background.js
chrome.declarativeNetRequest.updateSessionRules({  addRules: [{    id: 1,    priority: 1,    action: {      type: chrome.declarativeNetRequest.RuleActionType.MODIFY_HEADERS,      responseHeaders: [{        header: "X-Frame-Options",        operation: chrome.declarativeNetRequest.HeaderOperation.REMOVE      }],      requestHeaders: [{        header: "Referer",        operation: chrome.declarativeNetRequest.HeaderOperation.REMOVE      }]    },    condition: {      initiatorDomains: ["safefocusing.com"],      resourceTypes: [chrome.declarativeNetRequest.ResourceType.XMLHTTPREQUEST, chrome.declarativeNetRequest.ResourceType.MAIN_FRAME, chrome.declarativeNetRequest.ResourceType.SUB_FRAME]    }  }],  removeRuleIds: [1]});

Domain named by the rule condition

    • safefocusing.com

    Requests initiated by this host match the session rule that removes the listed response and request headers.

Remote filter list controls content-script injection

MediumunwantedCWE-829Dynamic sandbox

A request to safefocusing.com/filter/ returned HTTP 200.

What actually happens

You did this

The extension refreshes its settings after the background service worker starts.

The extension did this

It requests a domain list from safefocusing.com and uses the returned hosts to register content scripts.

The scripts are registered for all frames on HTTPS match patterns built from the response.

Captured request

GEThttps://safefocusing.com/filter/

HTTP 200 observed during dynamic analysis; no request body was recorded in the available evidence.

Fields that turn the remote list into injection rules

  • Remote list endpoint
    https://safefocusing.com/filter/

    This address supplies the list that decides which browsing locations receive the extension's page scripts.

  • Stored host list
    childSafetyUris

    The extension saves the returned list locally so later code can decide whether the current site is on that list.

  • Generated match pattern
    https://*.wikipedia.org/* (illustrative)

    Each returned host is converted into an HTTPS rule that covers that host's subdomains and paths.

  • Injected files
    icontent.js, icontent.css

    These extension files are the page scripts and styles that run when you browse to a matched host.

  • Frame coverage
    allFrames: true

    The rule applies inside embedded frames as well as the top-level page on a matched host.

The code that does this

The shipped bundle fetches the remote list and registers all-frame scripts

Readable version

Default Child Safety setting

background.js
const _ = p(te),  ae = {    enabled: !0,    autoBlocks: [{      name: "Child Safety",      slug: "childSafety",      enabled: !0    }, {      name: "Social Media",      slug: "socialMedia",      enabled: !1    }, {      name: "Streaming Services",      slug: "streamingServices",      enabled: !1    }],    customDomains: []  },  ie = async () => {    const s = await _.storage.local.get("settings");    return s.hasOwnProperty("settings") ? s.settings : ae  };

Remote hosts become all-frame content-script rules

background.js
async function s(t, g) {  if (t.length === 0) {    var l = await chrome.scripting.getRegisteredContentScripts({      ids: [g]    });    l.length > 0 && await chrome.scripting.unregisterContentScripts({      ids: [g]    });    return  }  try {    await chrome.scripting.unregisterContentScripts({      ids: [g]    })  } catch {}  const f = t.map(b => {    try {      const U = b.includes("://") ? b : `https://${b}`;      return "https://*." + new URL(U).host + "/*"    } catch {      return b    }  });  chrome.scripting.registerContentScripts([{    id: g,    matches: f,    allFrames: !0,    js: ["icontent.js"],    css: ["icontent.css"],    runAt: "document_end"  }])}const e = async t => {  const g = t.customDomains.filter(d => d.enabled).map(d => d.uri);  await s(g, "customDomains");  const l = ["facebook.com", "instagram.com", "twitter.com", "youtube.com", "x.com"],    f = t.autoBlocks.filter(d => d.enabled && d.slug == "socialMedia").length > 0;  await s(f ? l : [], "socialMedia");  const b = ["netflix.com", "hulu.com", "hbo.com", "hbo.com", "hbo.com"],    U = t.autoBlocks.filter(d => d.enabled && d.slug == "streamingServices").length > 0;  await s(U ? b : [], "streamingServices");  var R = [];  try {    var B = await fetch("https://safefocusing.com/filter/");    R = await B.json(), await chrome.storage.local.set({      childSafetyUris: R    })  } catch {}  const X = t.autoBlocks.filter(d => d.enabled && d.slug == "childSafety").length > 0;  await s(X ? R : [], "childSafety")};

Remote host involved in the rule generation path

    • safefocusing.com

    Provides the filter endpoint whose JSON response is used to derive content-script match patterns.

Where it sends data

Destinations our analysis observed Focus & Productivity Booster 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.

  • safefocusing.com

    Focus & Productivity Booster sends data to safefocusing.com. No other extension we have analyzed sends data here.

Updated 2 November 2026ekljakmipadncemihdnjamakjflfgnkg