Is Cash Catch safe?

High risk

Cash Catch runs on every site and sends the full URL, referrer, and hostname of each page you visit to its servers.

On every page you load, Cash Catch's content script transmits the full page URL (including paths and query strings), the referrer, and the hostname to rukthwaealso.com as a base64-encoded request. A service worker pulls remote configuration from hemostgracefu.org and rukthwaealso.com that controls when coupon popups appear and which affiliate tags are used. On supported merchant sites the extension silently opens and closes a hidden background tab to apply_affiliate, dropping affiliate-attribution cookies so its operator earns the commission on your purchase.

infov1.0.22Chrome Web Store
75Risk

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

Publishers can request a review.

Findings

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

Full page URLs and referrers sent to third-party server on every site visited

Every page you visit triggers Cash Catch to send its URL, referring URL, and the opener tab's hostname to rukthwaealso.com.

This fires on every navigation, on every site, not just shopping ones; the data is base64-encoded first.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You navigate to any website in the browser.

The extension's content script is injected on all URLs and fires automatically at document_idle.

The extension did this

The extension encodes the page URL, referrer, and opener tab hostname into a base64 blob and POSTs it to rukthwaealso.com/get_coupons.

This happens on every navigation including non-shopping sites like banking, health portals, and internal web apps.

02EvidenceNETWORK CAPTURE
Captured request
POSThttps://rukthwaealso.com/get_coupons?tid=1232664&osr=google.com&ver=1.0.22&ext=cash_catch&ref=google.com
JSON response containing coupon configurations and behavioral settings for the visited domain.
Headers
Content-Typetext/plain
Body
eyJyZWZlcnJlciI6Imh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS8iLCJwYWdlX3VybCI6Imh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vYWNjb3VudC9hYm91dC8_aGw9ZW4tVVMifQ==
03EvidenceOPAQUE REVEAL
Why you can't catch this in DevTools

The POST body is base64-encoded JSON, making the contents non-obvious in standard network monitoring tools that display the raw body.

What's actually being sent
{
  "referrer": "https://accounts.google.com/",
  "page_url": "https://www.google.com/account/about/?hl=en-US"
}
04EvidenceFIELD TABLE
Data sent in every request to rukthwaealso.com/get_coupons
FieldValueWhy it matters
Current page URL
https://www.google.com/account/about/?hl=en-USThe full URL of the page you just loaded, including path and query string.
Referrer URL
https://accounts.google.com/The URL of the page you came from, revealing navigation patterns and browsing sequences.
Visited hostname (query param)
osr=google.com&ref=google.comThe domain of the current site appears in the query string as the osr and ref parameters.
Opener tab hostname
parent: "mail.google.com"If the current tab was opened from another tab, the domain of that parent tab is included.
Extension version
ver=1.0.22The installed extension version is included in every request query string.
05EvidenceCODE COMPARE
The code that does this

Service worker code that encodes and transmits browsing context

What it actually does
bg/background.js:307-321 — building and sending the encoded bodybg/background.js
const encodedData = {};
if (referrer) encodedData.referrer = referrer;
if (pageUrl) encodedData.page_url = pageUrl;
const parentTabId = getSavedParent(senderTabId);
if (parentTabId) {
  try {
    const parentTab = await chrome.tabs.get(parentTabId);
    if (parentTab && parentTab.url) {
      encodedData.parent = new URL(parentTab.url).hostname;
    }
  } catch (e) {}
}
const base64Body = btoa(JSON.stringify(encodedData));

const response = await fetch(apiUrl, {
  method: 'POST',
  headers: { 'Content-Type': 'text/plain' },
  body: base64Body,
  keepalive: true
});
bg/background.js:294-300 — query string includes hostname and all tracking paramsbg/background.js
let apiUrl = `${Config.apiUrl}/get_coupons?tid=${tid}&osr=${encodeURIComponent(hostname)}&ver=${EXT_VERSION}&ext=cash_catch&ref=${encodeURIComponent(hostname)}`;

if (trackingParams && Object.keys(trackingParams).length > 0) {
  Object.keys(trackingParams).forEach(key => {
    apiUrl += `&${encodeURIComponent(key)}=${encodeURIComponent(trackingParams[key])}`;
  });
}
06EvidenceTHIRD PARTY LIST
Destination receiving full browsing history
  • rukthwaealso.com

    Primary data receiver. Collects full page URLs, referrers, and tab ancestry data via POST /get_coupons on every navigation across all sites.

SeverityHIGH
ClassUNWANTED
TypeUnexpected
CWECWE-829
SourceAI SANDBOX

Extension behavior on all sites governed by unsigned remote configuration

Cash Catch downloads its config from hemostgracefu.org and rukthwaealso.com on startup and at intervals.

This sets which sites trigger the popup, affiliate cookie behavior, consent timing, and cart detection sitewide, unsigned.

01EvidenceCAUSE EFFECT
What actually happens
You did this

The extension is installed and the service worker starts.

On startup and at server-defined refresh intervals, the service worker contacts two external servers for behavioral configuration.

The extension did this

The extension downloads unsigned config from hemostgracefu.org and rukthwaealso.com that controls popup behavior, affiliate triggering, and cart detection on every site.

The fetched config is stored locally with no signature or integrity check. Any change to the config without notifying the user alters how the extension behaves across all sites.

02EvidenceTEMPORAL PATTERN
When this fires
On every browser startup

Tracking parameters are fetched from rukthwaealso.com/gt on every service worker startup. Full behavioral config is fetched from hemostgracefu.org/api/conf on first run and then refreshed according to the server-supplied refresh_ms field in the config itself, meaning the refresh cadence is also server-controlled.

03EvidenceFIELD TABLE
Configuration keys delivered by hemostgracefu.org that control extension behavior
FieldValueWhy it matters
Popup timing config
current_tab: {cooldown_general_ms: 21600000}Controls how long the extension waits before showing coupon popups on new tabs and within the same tab.
Cart detection rules
cart_keywords: {enabled: true}, cart_only: {enabled: false}Defines which URLs and keywords are treated as shopping cart pages, triggering affiliate events.
Affiliate consent tag
mode: {tag: "aff_tid_9812"}The server can set the affiliate TID (tracking ID) and mode tag used for monetization events across all merchant sites.
Config refresh interval
refresh_ms: 3600000The server specifies how often the extension re-fetches its own config, giving the server perpetual update capability.
Consent cooldown
consent_cooldown: {enabled: true, cooldown_ms: 86400000}Controls how frequently the affiliate consent cookie is fired per domain visit.
04EvidenceCODE COMPARE
The code that does this

Config fetch with no integrity check

What it actually does
bg/background.js:132-154 — config fetch, no signature checkbg/background.js
async function fetchConfigFromServer(trackingParams) {
  if (!trackingParams || Object.keys(trackingParams).length === 0) {
    logMessage('No tracking params provided, using default config');
    return null;
  }

  try {
    const url = new URL(`https://hemostgracefu.org/api/conf`);
    url.searchParams.append('ver', EXT_VERSION);
    Object.keys(trackingParams).forEach(key => url.searchParams.append(key, trackingParams[key]));
    const response = await fetch(url.href);
    if (!response.ok) throw new Error('Config API request failed');

    const data = await response.json();
    if (data && data.message && data.message.settings) {
      return data.message.settings;  // accepted without any signature or hash check
    }
    throw new Error('Invalid config response structure');
  } catch (error) {
    logMessage('Error fetching config from server:', error);
    return null;
  }
}
bg/background.js:220-275 — config stored and refresh interval also server-controlledbg/background.js
async function getConfigData() {
  return new Promise((resolve) => {
    chrome.storage.local.get(['configData', 'configTimestamp'], async (result) => {
      const configData = result.configData;
      const configTimestamp = result.configTimestamp;

      if (!configData) {
        const fetchedConfig = await fetchConfigFromServer(trackingParams);
        if (fetchedConfig) {
          chrome.storage.local.set({
            configData: { settings: fetchedConfig },
            configTimestamp: Date.now(),
            // stored without integrity validation
          });
        }
        return;
      }

      // refresh interval is itself supplied by the server
      const refreshMs = configData.settings?.refresh_ms;
      if (refreshMs && configTimestamp) {
        const timeSinceFetch = Date.now() - configTimestamp;
        if (timeSinceFetch >= refreshMs) {
          const fetchedConfig = await fetchConfigFromServer(trackingParams);
          // again stored without any hash/signature check
        }
      }
    });
  });
}
05EvidenceTHIRD PARTY LIST
Remote servers delivering unsigned behavioral configuration
  • hemostgracefu.org

    Delivers the primary behavioral configuration JSON (popup timing, cart detection, affiliate consent rules, refresh cadence) that governs extension behavior on all visited sites.

  • rukthwaealso.com

    Delivers tracking params (affiliate TID, consent flags) via /gt. Also receives browsing data via /get_coupons: both a config source and a data exfil destination.

Data recipients

rukthwaealso.comhemostgracefu.org
Updated 17 September 2026cjbmfmeflcomeifhpeglfmpgmmhcopdo