Is Boomerang for Gmail safe?

Medium risk

Boomerang for Gmail is medium risk. Inbox Pause reads Gmail's GMAIL_AT cookie, its anti-CSRF token, granting account authority over internal endpoints incl. the Inbox-Paused filter. Testing confirmed it stays on Google's domains, but get_at_variable is publicly exposed too.…

Boomerangv1.9.5Chrome Web Store
45Risk

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

Publishers can request a review.

Findings

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-200
SourceAI SANDBOX

Reads Gmail's CSRF cookie to call Gmail's internal API as you

Inbox Pause reads Gmail's GMAIL_AT cookie, its anti-CSRF token, granting account authority over internal endpoints incl. the Inbox-Paused filter.

Testing confirmed it stays on Google's domains, but get_at_variable is publicly exposed too.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You click Pause Inbox (or Boomerang otherwise needs to manage the Inbox-Paused filter).

The extension did this

Boomerang reads Gmail's anti-CSRF cookie from document.cookie and uses it to call Gmail's internal filter-management API as you, installing the Inbox-Paused label-filter.

The cookie itself stays on Google domains in this build, it is used only to talk to mail.google.com, but the extension does extract it into a JavaScript variable that any future code path could ship anywhere.

02EvidenceFIELD TABLE
What the GMAIL_AT cookie is and what it lets the extension do:
FieldValueWhy it matters
GMAIL_AT cookie value
AF6bupPl26NI-Sp2H2U4wrG3iGIUnioyggGmail's anti-CSRF token. Whoever holds it can call Gmail's internal endpoints with full account authority: install filters, modify labels.
Gmail "ik" value
11abc2def3A second internal Gmail identifier the extension also reads from page state to construct authenticated calls.
Authenticated Gmail filter request
POST https://mail.google.com/mail/u/0/?ik=11abc2def3&at=AF6bupPl26NI-Sp2H2U4wrG3iGIUnioygg&view=up&act=df&pcd=1&mb=0&rt=cThe extension uses your token to POST to Gmail's filter endpoint, installing the Inbox-Paused-* label-filter Boomerang depends on.
Public exposure on api object
api.get.b4g_get_at_variable() // returns the live GMAIL_ATThis cookie-reader is also exposed as api.get.b4g_get_at_variable. Future or third-party code calling it gets your Gmail token.
03EvidenceCODE COMPARE
The code that does this

The cookie reader, the api-object exposure, and the authenticated Gmail call.

What it actually does
What's actually happening
// Pull Gmail's anti-CSRF token straight out of document.cookie.
function getGmailAt() {
  const start = document.cookie.indexOf('GMAIL_AT=') + 9;
  const end   = document.cookie.indexOf(';', document.cookie.indexOf('GMAIL_AT'));
  return document.cookie.substring(start, end);
}

// Use it (plus the in-page "ik" value) to act as you against Gmail's
// undocumented filter-management endpoint, installing/checking the
// Inbox-Paused-* filter that the Pause Inbox feature depends on.
const url = `${gmailBaseUrl}ik=${getGmailIk()}&at=${getGmailAt()}&view=up&act=df&pcd=1&mb=0&rt=c`;
fetch(url, { method: 'POST', body: 'tfi=none&' });

// Also exposed publicly on the bookmarklet's api object:
api.get.b4g_get_at_variable = getGmailAt;
04EvidencePLAIN NOTE
Confirmed: the token is not exfiltrated in this build

Dynamic analysis instrumented `document.cookie` reads and observed 216 reads in a single session (every Inbox-Pause-related action triggers them). A SQL grep of the captured outbound traffic — `SELECT COUNT(*) FROM requests WHERE url LIKE '%b4g.baydin%' AND body LIKE '%GMAIL_AT%'` — returned 0 rows. The token is used only to call mail.google.com itself in this version.

That is the safer outcome. The risk is structural: the value is yanked into a JS string and exposed on a public `api.get.b4g_get_at_variable` function. Any future code path (or an attacker-controlled script that finds its way onto a Gmail tab and can call into Boomerang's window-scope api) that ships the result of that function is a one-line patch away from full Gmail-account takeover-level credential exposure.

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-200
SourceAI SANDBOX

Every interaction sent to Google Analytics with a per-user UUID

Boomerang fires a GA event for nearly every action (~307 types), each carrying a stable localStorage UUID (b4g_ga_cid) that lets GA correlate everything you do.

Events POST from the background worker, so page-level blockers miss them.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You click anything Boomerang touches, Pause Inbox, Schedule Send, opening Compose, the OAuth dialog.

The extension did this

The background service worker POSTs a Google Analytics event with your stable per-user UUID, the action you took, and a label.

Because the request comes from the extension's service worker (not the Gmail page), browser tracker-blockers running in the page do not see or block it.

02EvidenceNETWORK CAPTURE
Captured request
POSThttps://www.google-analytics.com/mp/collect?measurement_id=G-48B3G8LRPQ&api_secret=<redacted>
204 No Content (GA Measurement Protocol acknowledges receipt). 3 such POSTs captured during dynamic analysis, covering: opening Gmail (automatic_oauth_dialog/show), the OAuth login attempt (automatic_oauth_dialog/login_attempt), and the resulting flow (oauth_flow/login). The same client_id UUID appears on every event, that is the stable cross-session identifier.
Headers
Originchrome-extension://mdanidgdpmkimeiiojknlnekblgmpdll
Content-Typetext/plain;charset=UTF-8
Body
{
  "client_id": "48285cd7-e1b9-4da4-89a1-c1617887469f",
  "events": [
    {
      "name": "automatic_oauth_dialog",
      "params": {
        "action": "show",
        "label": "first_open"
      }
    }
  ]
}
03EvidenceFIELD TABLE
What goes out on every event:
FieldValueWhy it matters
client_id (your stable UUID)
48285cd7-e1b9-4da4-89a1-c1617887469fA persistent random ID created on first run, stored in localStorage, and attached to every analytics event until you clear site storage.
events[].name (event category)
automatic_oauth_dialogThe Boomerang feature class you interacted with. The bookmarklet emits ~307 distinct names, covering essentially every UI action.
events[].params.action
showWhat you did within that feature.
events[].params.label
first_openOptional sub-context for the action, feature variant, source, etc.
measurement_id (in URL)
G-48B3G8LRPQIdentifies the developer's GA4 property. Hardcoded in the extension and visible to every user on every event.
api_secret (in URL)
uIAXRk5NR3m2Mef57TbpxQThe credential GA uses to authorize the POST, hardcoded and visible to every user; see Claim 5870 for the security implication.
04EvidenceCODE COMPARE
The code that does this

From the page → content script hop → background SW → Google Analytics POST.

What it actually does
End-to-end flow
// 1. Page-side code in the bookmarklet does:
window.postMessage({type: 'B4G_TRACK_EVENT', trackedEventData: ['oauth-flow', 'login']}, '*');

// 2. The b4g.js content script forwards it to the background SW.
// 3. The background SW assigns the persistent UUID and POSTs to GA.
//    From your perspective the request originates from the extension, not the page,
//    so any blocker that only filters page requests will not see it.
fetch(`https://www.google-analytics.com/mp/collect`
      + `?measurement_id=G-48B3G8LRPQ&api_secret=<redacted>`,
  { method: 'POST',
    body: JSON.stringify({
      client_id: localStorage.b4g_ga_cid,   // your stable per-user UUID
      events: [{ name: 'oauth_flow', params: { action: 'login' } }]
    })
  });
05EvidenceSTORAGE DUMP
What's stored on your device

This string is your per-user identifier in GA across every Boomerang interaction, surviving restarts, recreated only if you clear storage.

LocationPage localStorage on mail.google.com, key b4g_ga_cid
Contents
48285cd7-e1b9-4da4-89a1-c1617887469f
06EvidenceTHIRD PARTY LIST
Where the analytics events go:
  • www.google-analytics.com

    Receives Measurement Protocol POSTs to /mp/collect, credited to GA4 property G-48B3G8LRPQ. Google processes the data under its standard terms; Baydin Inc is the controller.

SeverityMEDIUM
ClassUNWANTED
TypeUnexpected
CWECWE-359
SourceAI SANDBOX

Your Gmail address is sent to b4g.baydin.com on every page open and click

Boomerang reads your Gmail address on every Gmail load and sends it to b4g.baydin.com as guser, automatically and on every feature used.

It's the vendor's user ID and, being in the URL, lands in access logs too.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You open Gmail (or click any Boomerang button).

The extension did this

Boomerang reads your full Gmail address out of the page header and tacks it onto a request to its own server as the "guser" parameter.

It happens automatically the moment Gmail loads, no Boomerang button click required for the first request.

02EvidenceNETWORK CAPTURE
Captured request
GEThttps://b4g.baydin.com/mailcruncher/hasseentutorial?guser=robertfinwitch%40gmail.com&image=True
Captured automatically on Gmail load with no Boomerang button clicked. The live test account address robertfinwitch@gmail.com appears URL-encoded in the query string. A second capture, GET /mailcruncher/checklogin2?guser=robertfinwitch%40gmail.com&includecsrf=True, fires the moment Pause Inbox is clicked.
Headers
Accept*/*
Originhttps://mail.google.com
Refererhttps://mail.google.com/
03EvidenceFIELD TABLE
Endpoints observed (or grep-confirmed in source) sending your Gmail address as guser=:
FieldValueWhy it matters
/mailcruncher/hasseentutorial
?guser=robertfinwitch%40gmail.com&image=TrueFires automatically on Gmail load to check if you've seen Boomerang's tutorial. Your address goes out before you touch anything.
/mailcruncher/checklogin2
?guser=robertfinwitch%40gmail.com&includecsrf=TrueFires on Pause Inbox click. Tells the vendor you are an active Boomerang user under this Gmail address.
checkIfHasSeenAnnouncementsAndFTUEs
POST guser=robertfinwitch%40gmail.comPolls server for in-product announcements scoped to your specific email address.
schedulesend/return/recurring
?guser=robertfinwitch%40gmail.comSends your address whenever you schedule, snooze, or set up a recurring email, links every scheduled-mail action to your identity.
sendlater, boomerangfrom* endpoints
?guser=robertfinwitch%40gmail.comSent on every Boomerang/send-later from a conversation. Builds a record of which messages you delay and when.
/tr/track-sender-open
?guser=robertfinwitch%40gmail.comOpen-tracking endpoint. Includes your address so opens you triggered are tied back to you, not just the recipient.
dialog/subs/insights/login/contacts
https://b4g.baydin.com/insights/insightsfromgmail?guser=robertfinwitch%40gmail.comAll UI links Boomerang opens for you carry your address in the URL, useful for the vendor's tracking, exposed in browser history.
04EvidenceCODE COMPARE
The code that does this

How the address is extracted, and a representative endpoint that ships it.

What it actually does
What the scrape does, in plain terms
// Walk the Gmail header, look for an email-shaped string in any aria-label.
// Fall back to the browser tab title if the header has no match.
function getGmailAddress() {
  for (const a of document.querySelectorAll('header a[aria-expanded]')) {
    const m = /[\w.+\-]+@[\w.\-]+\.\w+/.exec(a.getAttribute('aria-label'));
    if (m) return m[0];
  }
  for (const w of document.title.split(' ')) {
    const m = /[\w.+\-]+@[\w.\-]+\.\w+/.exec(w);
    if (m) return m[0];
  }
  return '';
}

// Then every server call looks like this:
fetch(`https://b4g.baydin.com/mailcruncher/<endpoint>?guser=${encodeURIComponent(getGmailAddress())}&...`);
05EvidenceTHIRD PARTY LIST
Where your Gmail address ends up:
  • b4g.baydin.com

    Boomerang's primary backend (Baydin Inc). Receives your Gmail address as guser= on every feature use, plus the tutorial check on load. It's the vendor's primary user identifier.

06EvidenceARTIFACT
Reproduce it yourself

Live-tails Chrome's net log for any request to b4g.baydin.com that contains a guser= parameter. Lets you confirm in your own browser that your Gmail address is leaving on every Boomerang interaction.

RequiresbashGoogle Chrome with --log-net-log support
watch-baydin-guser.sh · sh
#!/usr/bin/env bash
# watch-baydin-guser.sh — see your Gmail address leaving in real time.
#
# Usage: launch Chrome with --log-net-log=/tmp/netlog.json --net-log-capture-mode=IncludeSensitive
# then run this script. Open Gmail with Boomerang installed and click around.
set -euo pipefail
LOG="${1:-/tmp/netlog.json}"
until [[ -s "$LOG" ]]; do sleep 1; done
tail -F "$LOG" | grep --line-buffered -oE 'https://b4g\.baydin\.com/[^"]*guser=[^&"]*' | while read -r url; do
  echo "$(date -u +%FT%TZ)  $url"
done
How to run it
  1. 1
    Quit Chrome.
  2. 2
    Relaunch: google-chrome --log-net-log=netlog.json --net-log-capture-mode=IncludeSensitive.
  3. 3
    Run ./watch-baydin-guser.sh netlog.json.
  4. 4
    Open Gmail: hasseentutorial?guser=YOUR_EMAIL appears within seconds, unclicked.
Updated 20 September 2026mdanidgdpmkimeiiojknlnekblgmpdll