Is BeFrugal Tab safe?

High risk

BeFrugal is high risk. Every browser open, and hourly after, BeFrugal Tab reads your full installed-extension list, names, descriptions, IDs, versions, and sends it to a BeFrugal server, revealing which security tools, password managers, and VPNs you use.…

befrugaldevv2024.0.43Chrome Web Store
77Risk
Who publishes it

befrugaldev - 2 other listings from the same operator, 2 of them carrying a finding

What this publisher told the store about itself, and the other listings that told it the same thing.

Publisher
befrugaldev

Same store account

2 other listings published from this account, 110k+ users between them. 2 of them carry a finding.

Shared hosts - 3 hostnames

Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.

sunstreamlabs.com
Also called by 1 other listing: Lucky PDF Converter
partialjs.befrugal.com
Also called by 3 other listings, including Rewards, BeFrugal: Automatic Coupons, Highest CashBack
tbwsjsan.bfrl.us
Also called by 3 other listings, including Rewards, BeFrugal: Automatic Coupons, Highest CashBack

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

Publishers can request a review.

Findings

BeFrugal Tab transmits your full browser extension inventory every hour

Every browser open, and hourly after, BeFrugal Tab reads your full installed-extension list, names, descriptions, IDs, versions, and sends it to a BeFrugal server, revealing which security tools, password managers, and VPNs you use.

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

The RegenDB alarm fires, or the daily digest hasn't run yet today.

This happens automatically on startup and once every 60 minutes, with no user interaction required.

The extension did this

Your complete browser extension list is read and sent to BeFrugal's servers.

Every extension you have installed, including its name, internal ID, description, and version, is collected and uploaded in a single POST request.

Captured request
POSThttps://tbwsjs.befrugal.com/wssimple.asmx/UserExtensionsUpsert

Server upserts the extension inventory against the UserToken; no body returned on success.

Headers
Content-Type
application/x-www-form-urlencoded
Body
extensions=[{"id":"cjpalhdlnbpafiamejdnhcphjbkeiagm","name":"Adblock%20for%20Youtube%E2%84%A2","description":"Block%20ads%20on%20YouTube","version":"1.9.2"},{"id":"nkbihfbeogaeaoehlefnkodbefgpgknn","name":"MetaMask","description":"Ethereum%20browser%20extension","version":"11.13.1"},{"id":"cfhdojbkjhnklbpkdaibdccddilifddb","name":"Adblock%20Plus","description":"Block%20ads","version":"3.23"}]&UserToken=a8f3c1d7-4e2b-4a99-b891-2f3c4d5e6f7a&toolbarversion=ch-bfrwds2024.0.43
Fields transmitted per installed extension
  • Extension ID
    nkbihfbeogaeaoehlefnkodbefgpgknn

    The unique Chrome extension identifier, stable across versions and browsers. Reveals every security tool, password manager, and VPN you run.

  • Extension name
    MetaMask

    The human-readable display name of each extension you have installed.

  • Extension version
    11.13.1

    The installed version of each extension, which can indicate whether you are running outdated software with known vulnerabilities.

  • Extension description
    Ethereum browser extension

    The full description text of each extension, as shown in the Chrome Web Store.

  • User token
    a8f3c1d7-4e2b-4a99-b891-2f3c4d5e6f7a

    A persistent account token that ties each transmission to your BeFrugal identity.

The code that does this

Extension enumeration and upload, background.js:711-727

Readable version
chrome.management.getAll(function(extensions) {  var body = "extensions=" + JSON.stringify(    extensions.map(function(ext) {      return {        id: ext.id,        name: encodeURIComponent(ext.name),        description: encodeURIComponent(ext.description),        version: encodeURIComponent(ext.version)      };    })  ) + "&UserToken=" + userToken + "&toolbarversion=" + toolbarVersion;  fetch("https://tbwsjs.befrugal.com/wssimple.asmx/UserExtensionsUpsert", {    method: "POST",    headers: { "Content-Type": "application/x-www-form-urlencoded" },    body: body  });});
When this fires

Every 1 hour

The RegenDB alarm fires every 60 minutes. On each tick, digestRequest() checks whether the daily digest has already run; if not, it calls getDigestPartial(), which executes the chrome.management.getAll() upload.

Destination server
    • tbwsjs.befrugal.com

    BeFrugal-owned backend that receives and stores the extension inventory alongside the user's account token (UserExtensionsUpsert endpoint).

BeFrugal Tab transmits UI interaction history to BeFrugal daily

Each day BeFrugal Tab records how you've used its interface: panels opened, search engine used, deal/reward clicks, and toolbar search/navigation counts.

This behavioral profile is sent to BeFrugal's servers in the daily digest request.

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

You click deals, use the rewards toolbar, or search through the extension.

Each interaction type is counted and timestamped in local storage as it occurs.

The extension did this

Your interaction history and current UI configuration are sent to BeFrugal once per day.

A parameter string encoding which panels are visible, which search engine you use, and how many times you clicked each feature is included in the daily digest POST.

Captured request
POSThttps://partialjs.befrugal.com/wssimple.asmx/RetailerDigestPartial

Server returns JSON with retailer deals and user account data for new tab page population.

Headers
Content-Type
application/x-www-form-urlencoded
Body
toolbarversion=ch-bfrwds2024.0.43&usertoken=a8f3c1d7-4e2b-4a99-b891-2f3c4d5e6f7a&toolbarmetrics=,KeepChangesDisplayed.1.1776506928,KeepChanges.1.1776506942,cleanup.1,isYahoo.1,RewardsBar.1,RewardsSplash.1
Interaction signals included in the toolbarmetrics parameter
  • Search engine choice
    isYahoo.1

    Reveals whether you use Yahoo, Google, Bing, or DuckDuckGo as your default through the toolbar.

  • Deal clicks
    DealClick.3.1776498000

    Number of times you clicked on a cashback deal, counted since last digest.

  • Rewards bar interactions
    RewardsBar.1,RewardsActivity.1

    Whether the rewards header bar and activity panels are visible, indicating how actively you use the rewards features.

  • Omnibar search count
    RewardsToolbarSearch.7.1776501234

    How many searches you have performed through the toolbar's search box.

  • Shortcut clicks
    ShortcutClicks.2.1776502100

    Number of times you clicked the custom shortcuts on the new tab page.

  • User token
    a8f3c1d7-4e2b-4a99-b891-2f3c4d5e6f7a

    The persistent account identifier that ties this interaction history to your BeFrugal account.

The code that does this

Metric collection and upload, background.js:659-734

Readable version

setMetric — records each interaction

background.js:659
setMetric: function(eventName, increment, value) {  chrome.storage.local.get("analytics").then(function(stored) {    var analytics = stored ? stored.analytics || stored : {};    if (increment) value = (analytics[eventName] || 0) + 1;    analytics[eventName] = value;    analytics.MetricTime = analytics.MetricTime || {};    analytics.MetricTime[eventName] = parseInt(new Date().getTime() / 1000);    chrome.storage.local.set({ analytics: analytics });  });},

getMetricParams — builds toolbarmetrics query string

background.js:671
getMetricParams: function(analyticsData) {  analyticsData = analyticsData || {};  var paramStr = "&toolbarmetrics=";  var keys = Object.keys(analyticsData);  for (var i = keys.length - 1; i >= 0; i--) {    if (keys[i] !== "MetricTime") {      var val = analyticsData[keys[i]];      if (val === true) val = "1";      else if (val === false) val = "0";      var timestamp = (analyticsData.MetricTime || {})[keys[i]];      paramStr += (i === keys.length - 1 ? "" : ",") + keys[i] + "." + val + (timestamp ? "." + timestamp : "");    }  }  return new Promise(function(resolve) {    chrome.storage.local.get(      ["searchEngine","extensionMode","ctl00_MainContent_dvClock","cleanUpNoClockImage",       "dealsWrapper","favoriteRetailersContainer","bonusCashbackPanel","weatherPanel",       "rewardsHeaderBar","rewardActivityContainer","topSites"],      function(prefs) {        if (prefs) {          var engine = prefs.searchEngine || "Yahoo";          paramStr += ",cleanup." + (prefs.extensionMode === "cleanUp" ? 1 : 0);          if (engine === "Yahoo")      paramStr += ",isYahoo.1";          if (engine === "Google")     paramStr += ",isGoogle.1";          if (engine === "Bing")       paramStr += ",isBing.1";          if (engine === "DuckDuckGo") paramStr += ",isDuckDuckGo.1";          if (prefs.rewardsHeaderBar          === "visible") paramStr += ",RewardsBar.1";          if (prefs.rewardActivityContainer   === "visible") paramStr += ",RewardsActivity.1";          if (prefs.dealsWrapper              === "visible") paramStr += ",RewardsDeals.1";          if (prefs.bonusCashbackPanel        === "visible") paramStr += ",RewardsBonusCBRetailers.1";          if (prefs.favoriteRetailersContainer=== "visible") paramStr += ",RewardsFavorites.1";          if (prefs.weatherPanel             === "visible") paramStr += ",RewardsWeather.1";          if (prefs.ctl00_MainContent_dvClock === "visible") paramStr += ",RewardsClock.1";          if (prefs.cleanUpNoClockImage       === "visible") paramStr += ",RewardsSplash.1";          if (prefs.flashCashbackSection      === "visible") paramStr += ",RewardsFlash.1";          resolve(paramStr);        }      }    );  });},
Destination server
    • partialjs.befrugal.com

    BeFrugal-owned backend that receives the daily RetailerDigestPartial request carrying UI interaction metrics and panel state alongside the user's account token.

BeFrugal Tab leaks your most-visited site hostnames to Google on every new tab

Granting BeFrugal Tab access to top-visited sites, to populate new-tab shortcuts, makes each hostname transmit to Google's favicon service immediately, one GET per top site, disclosing that history whenever the new tab loads.

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

You grant the extension permission to see your most-visited sites, and the new tab page loads.

This happens once when you first click 'Add Shortcut' and approve the topSites prompt, and again each time the new tab renders the shortcuts.

The extension did this

The hostname of each of your most-visited sites is sent to Google in a separate HTTP request.

The extension sets an img.src to http://www.google.com/s2/favicons?sz=64&domain=<hostname> for each top site, which causes your browser to make a GET request that reveals each hostname to Google.

Captured request
GEThttp://www.google.com/s2/favicons?sz=64&domain=mail.google.com

Google returns a favicon image (16x16 or 32x32 PNG). Seven such requests observed in DA: mail.google.com, youtube.com, yahoo.com, facebook.com, twitter.com, weather.com, wikipedia.org.

The code that does this

Favicon lookup that discloses top-site hostnames, PageScript.js:968-1014

Readable version
var displayShortcut = function(name, url, callback) {  var editAttr = document.getElementById("addShortcut").getAttribute("edit-shortcut");  var slot = document.querySelector(    editAttr ? '[shortcut="' + editAttr + '"]' : ".shortcutGreyOuterContainer.inactive"  );  if (slot) {    slot.classList.remove("inactive");    slot.querySelector(".addShortcutText").innerText = name;    slot.onclick = function() {      digest.setMetric("ShortcutClicks", true);      window.open(url, "_self");    };    // Sends the URL's domain to Google to fetch a favicon icon    slot.querySelector("img").src =      "http://www.google.com/s2/favicons?sz=64&domain=" + encodeURIComponent(url);    if (callback) callback();  }};
What Google receives in each request
  • Top-visited hostname
    youtube.com

    The domain of each of your most-visited websites is sent to Google as the domain= query parameter.

  • Full shortcut URL
    https://mail.google.com/mail/u/0/#inbox

    The shortcut's full URL, including path, goes to encodeURIComponent before sending, so full URLs, not just domains, can be disclosed.

Destination receiving top-site disclosures
    • www.google.com

    Google favicon service, receives domain= parameter containing each of your top-visited hostnames via the /s2/favicons endpoint. Google is not affiliated with BeFrugal.

What it can do

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

    *://*.befrugal.com/*

  • Read and change your data on bfrl.us

    *://*.bfrl.us/*

  • Add items to the right-click menu

    contextMenus

  • Store data in your browser

    storage

  • See, disable and uninstall your other extensions, including your security ones

    management

  • Schedule its own background tasks

    alarms

  • Run searches with your default search engine

    search

Updated 30 September 2026dmgghlknphpmkpejiogmpgllncfdpffm