Is Salesloft Connect safe?

Medium risk

Salesloft is medium risk. DA observed Salesloft Connect's InboxSDK POST to Pub/Sub (pubsub.googleapis.com/v1/projects/mailfoogae/topics/events:publish) on Gmail load: type=sdkPassive, origin=mail.google.com, session/ext/app IDs. It queues an email hash pre-upload.

Salesloft Extensionsv1.7.34Chrome Web Store
45Risk
Who publishes it

Salesloft - no other listings under this identity

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

Publisher
Salesloft Extensions
Declared legal entity
Salesloft
Registered address
1180 W Peachtree St NW Suite 2400, Atlanta, GA 30309-3482, US
Registered contact
Nick Dahm

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

Publishers can request a review.

Findings

InboxSDK transmits Gmail events to Google Cloud Pub/Sub

DA observed Salesloft Connect's InboxSDK POST to Pub/Sub (pubsub.googleapis.com/v1/projects/mailfoogae/topics/events:publish) on Gmail load: type=sdkPassive, origin=mail.google.com, session/ext/app IDs.

It queues an email hash pre-upload.

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

You use Gmail with Salesloft Connect installed.

The extension did this

The bundled InboxSDK library queues a Gmail usage event and posts the batch to Google Cloud Pub/Sub.

The observed event was noJSFrameElementFound and the source adds an email-derived hash, session identifier, origin, and app identifiers to queued events.

Fields tied to the observed Gmail event
  • Event type
    sdkPassive / noJSFrameElementFound

    Shows which Gmail-side condition was recorded during your session.

  • Gmail origin
    https://mail.google.com

    Ties the event to activity on Gmail rather than a generic browser session.

  • Extension identifier
    ejgmneenioanldgngdomlfnbcbffmchf

    Identifies which installed extension generated the event.

  • Session identifier
    sessionId field present in the decoded event

    Lets repeated Gmail events from the same browser session be associated with each other.

  • Email-derived hash
    emailHash field populated from the Gmail account

    Lets the event be associated with the Gmail account without sending the raw address in the queued object.

  • InboxSDK app identifiers
    appIds field present in the decoded event

    Links the Gmail event to the InboxSDK app integration running inside the extension.

Captured request
POSThttps://pubsub.googleapis.com/v1/projects/mailfoogae/topics/events:publish?key=AIzaSyAwlvUR2x3OnCeas8hW8NDzVMswL5hZGg8

Dynamic analysis observed a POST to the Pub/Sub publish endpoint; the recorded evidence retained decoded event fields but not the full request body.

Headers
Content-Type
application/json
Authorization
Bearer <redacted>
The code that does this

InboxSDK queues Gmail events, fetches an OAuth token, and posts batches to Pub/Sub

Readable version

Queue event fields and mark the document for flushing

deobfuscated/gmail-sidebar.bundle.js
function P(e,t,n,i){if(i&&"object"!=typeof i)throw Error("properties must be object or null: "+i);let c={type:t,event:n,timestamp:1e3*Date.now(),origin:document.location.origin,sessionId:E,emailHash:o,loaderVersion:a,implementationVersion:r,properties:i};"gmail"!=t?Object.assign(c,{extensionId:p(),appIds:D(e)}):Object.assign(c,{appIds:D(null,!1)}),"undefined"!=typeof document&&(W.add(c),document.documentElement.setAttribute("data-inboxsdk-last-event",""+Date.now()))}

Fetch the InboxSDK OAuth token and publish the batch

deobfuscated/gmail-sidebar.bundle.js
let j=null;function H(e){return Date.now()+6e5>e}async function F(){let{text:e}=await (0,d.A)({url:"https://api.inboxsdk.com/api/v2/events/oauth",XMLHttpRequest:(0,A.np)()}),t=JSON.parse(e);return H(t.expirationDate)&&(console.warn("Got an apparently already expired token. Assuming our clock is busted..."),t.expirationDate=Date.now()+18e5),t}async function $(){let e=j;return e&&!H(e.expirationDate)?e:j=await F()}S&&"undefined"!=typeof document&&"undefined"!=typeof MutationObserver&&(0,y.A)(document.documentElement,{attributes:!0,attributeFilter:["data-inboxsdk-last-event"]}).map(()=>null).throttle(12e4).onValue(function(){let e=W.removeAll();0!==e.length&&(async function(){let{oauthToken:t}=await $();await (0,d.A)({url:`https://pubsub.googleapis.com/v1/projects/mailfoogae/topics/events:publish?key=${encodeURIComponent("AIzaSyAwlvUR2x3OnCeas8hW8NDzVMswL5hZGg8")}`,method:"POST",headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"},data:JSON.stringify({messages:[{data:w.from(JSON.stringify({data:e,timestamp:1e3*Date.now()})).toString("base64")}]})})})().catch(e=>{T.error(e,{type:"Failed to log events"})})})

Observed passive event source in the page-world bundle

deobfuscated/pageWorld.bundle.js
function tT() {            let t = null,              e = top.document.getElementById("js_frame");            e ? t = e.contentDocument.defaultView : v.eventSdkPassive("noJSFrameElementFound"),              function(t, e) {                let n = [],                  r = [];                {                  let e = t.XMLHttpRequest;                  t.XMLHttpRequest = k(e, n, {                    logError: tS                  })                }                if (e) {                  let t = e.XMLHttpRequest;                  e.XMLHttpRequest = k(t, r, {                    logError: tS                  })                }                try {                  let t = u()(document.querySelectorAll("script:not([src])"), t => t.text && t.text.slice(0, 500).indexOf("var VIEW_DATA=[[") > -1);                  if (t) {                    let e = t.text.indexOf("["),                      n = t.text.lastIndexOf("]"),                      r = t.text.slice(e, n + 1);                    $(M.eF([M.XX(r)]))                  }                } catch (t) {                  v.error(t, "Failed to process preloaded thread identifiers")                }                document.addEventListener(B.tellMeThisThreadIdByDatabase, function(t) {                  try {                    if (!(t.target instanceof HTMLElement)) throw Error("event.target is not an HTMLElement");                    let e = function(t) {                      let e = P(t);                      if (e === R) return;                      let n = G(e),                        r = F.get(n);                      if ("string" == typeof r) return r                    }(t.target);                    e && t.target.setAttribute("data-inboxsdk-threadid", e)                  } catch (t) {                    v.error(t, "Error in inboxSDKtellMeThisThreadIdByDatabase")                  }                }), document.addEventListener(B.tellMeThisThreadIdByClick, function(t) {                  try {                    if (!(t.target instanceof HTMLElement)) throw Error("event.target is not an HTMLElement");                    let e = function(t) {                      P(t);                      let e = function(t, e) {                        let n = t.parentElement;                        for (; n;) {                          if (e(n)) return n;                          n = n.parentElement                        }                        return null                      }(t, t => "DIV" === t.nodeName && "main" === t.getAttribute("role"));                      if (!e) throw Error("Can't operate on disconnected thread row");                      let n = e.querySelector("td.PE") || e.querySelector("tr"),                        r = V(t),                        i = r && function(t) {                          var e = (0, D.parse)(t).th;                          if (!e) {                            var n = t.match(/#(.*)/);                            n && (t = decodeURIComponent(decodeURIComponent(n[1])), e = (0, D.parse)(t).th)                          }                          return e.replace("#", "")                        }(r);                      return n && V(n), i                    }(t.target);                    e && t.target.setAttribute("data-inboxsdk-threadid", e)                  } catch (t) {                    v.error(t, "Error in inboxSDKtellMeThisThreadIdByClick")                  }                }), document.addEventListener("inboxSDKtellMeThisMessageDate", function(t) {                  tn(t, "data-inboxsdk-sortdate", t => t.date)                }), document.addEventListener("inboxSDKtellMeThisMessageRecipients", function(t) {                  tn(t, "data-inboxsdk-recipients", t => t.recipients ? t.recipients : null)                });                {                  let t = {};                  _.default.fromEvents(document, "inboxSDKregisterComposeRequestModifier").onValue(e => {                    let {                      detail: n                    } = e, r = n.composeid || n.draftID;                    t[r] || (t[r] = []), t[r].push(n.modifierId)                  }), _.default.fromEvents(document, "inboxSDKunregisterComposeRequestModifier").onValue(e => {                    let {                      detail: n                    } = e, {                      keyId: r,                      modifierId: i                    } = n;                    t[r] = t[r].filter(t => t !== i), 0 === t[r].length && delete t[r]                  }), r.push({                    isRelevantTo: function(t) {                      return "sm" === t.params.act                    },                    originalSendBodyLogger: function(t, e) {                      tO({                        type: "emailSending",                        body: e                      })                    },                    requestChanger: async function(e, n) {                      let r = D.parse(n.body),                        o = r.composeid,                        s = t[r.composeid];                      if (!s || 0 === s.length) return n;                      for (let t = 0; t < s.length; t++) {                        let e = s[t],                          n = _.default.fromEvents(document, "inboxSDKcomposeRequestModified").filter(t => {                            let {                              detail: n                            } = t;                            return n.composeid === o && n.modifierId === e                          }).take(1).map(t => {                            let {                              detail: e                            } = t;                            return e.composeParams                          }).toPromise();                        tO({                          type: "inboxSDKmodifyComposeRequest",                          composeid: o,                          modifierId: e,                          composeParams: {                            body: r.body,                            isPlainText: "1" !== r.ishtml                          }                        }), r = Object.assign({}, r, await n)                      }                      return Object.assign({}, n, {                        body: function(t) {                          let e = i()(t),                            n = `=${tj(e.to,"to")}&=${tj(e.cc,"cc")}&=${tj(e.bcc,"bcc")}`;                          return delete e.to, delete e.bcc, delete e.cc, n + "&" + D.stringify(e)                        }(r)                      })                    },                    afterListeners: function(e) {                      if (200 === e.status && (tO({                          type: "emailSent",                          responseText: e.originalResponseText,                          originalSendBody: e.originalSendBody                        }), e.originalSendBody)) {                        let n = D.parse(e.originalSendBody);                        delete t[n.composeid]                      }                    }                  }), r.push({                    isRelevantTo: function(t) {                      return "sd" === t.params.act                    },                    originalSendBodyLogger: function(t, e) {                      tO({                        type: "emailDraftSaveSending",                        body: e                      })                    },                    afterListeners: function(t) {                      200 === t.status && tO({                        type: "emailDraftReceived",                        responseText: t.originalResponseText,                        originalSendBody: t.originalSendBody,                        connectionDetails: {                          method: t.method,                          url: t.url,                          params: t.params,                          responseType: t.responseType                        }                      })                    }                  });                  {                    let e = new WeakMap,                      r = new WeakMap,                      i = new WeakMap;                    n.push({                      isRelevantTo: t => /sync(?:\/u\/\d+)?\/i\/s/.test(t.url),                      originalSendBodyLogger(t) {                        if (t.originalSendBody) {                          let n = tE(t.originalSendBody);                          if (!n) return;                          let {                            draftID: o                          } = n;                          switch (n.type) {                            case "FIRST_DRAFT_SAVE":                              i.set(t, o);                              break;                            case "DRAFT_SAVE":                              r.set(t, o);                              break;                            case "SEND":                              e.set(t, o), tO({                                type: "emailSending",                                draftID: o                              })                          }                        }                      },                      requestChanger: async function(e, n) {                        let r = tE(n.body);                        if (!r || "SEND" !== r.type) return n;                        let {                          draftID: i                        } = r, o = t[i];                        if (!o || 0 === o.length) return n;                        let s = r.body;                        for (let t = 0; t < o.length; t++) {                          let e = o[t],                            n = _.default.fromEvents(document, "inboxSDKcomposeRequestModified").filter(t => {                              let {                                detail: n                              } = t;                              return n.draftID === i && n.modifierId === e                            }).take(1).map(t => {                              let {                                detail: e                              } = t;                              return e.composeParams                            }).toPromise();                          tO({                            type: "inboxSDKmodifyComposeRequest",                            draftID: i,                            modifierId: e,                            composeParams: {                              body: s,                              isPlainText: !1                            }                          }), s = (await n).body                        }                        return Object.assign({}, n, {                          body: function(t, e) {                            let n = JSON.parse(t);                            try {                              if (Array.isArray(n)) {                                let r = function(t, e) {                                  let n = tp(t);                                  if (!n) return null;                                  let r = n.messageId,                                    i = t[1]?.[0];                                  if (!Array.isArray(i)) return null;                                  for (let n of i) {                                    if (!Array.isArray(n) || !Array.isArray(n[1])) break;                                    let i = n[1];                                    if (!t_(i[0])) break;                                    let o = tm(i);                                    if (o?.parsedMsg.messageId === r && "SEND" === tx(o.parsedMsg.actions)) return function(t, e) {                                      if (Array.isArray(t)) t[8][1][0][1] = e                                    }(o.originalMsg, e), t                                  }                                  return null                                }(n, e);                                if (r) return JSON.stringify(r);                                return t                              }                            } catch (t) {                              v.eventSdkPassive("connection.requestResponseParsingFailed", {                                replaceBodyFailed: t                              })                            }                            if (!e) return t;                            let r = JSON.parse(t),                              i = r[2] && r[2][1];                            if (!i) return t;                            let o = i.filter(t => {                              let e = t[2] && t[2][2] && (t[2][2][14] || t[2][2][2]);                              return e && e[1] && e[1][1] && e[1][1].indexOf("msg-a:") > -1                            });                            if (!o.length) return t;                            let s = o.find(t => {                              let e = t[2] && t[2][2] && (t[2][2][14] || t[2][2][2]);                              return e[1][11] && c()(e[1][11], tf).length === tf.length                            });                            return s ? ((s[2] && s[2][2] && (s[2][2][14] || s[2][2][2]))[1][9][2][0][2] = e, JSON.stringify(r)) : t                          }(n.body, s)                        })                      },                      afterListeners(t) {                        if (e.has(t) || r.has(t) || i.has(t)) {                          let n = () => {                              tO({                                type: "emailSendFailed",                                draftID: o                              }), e.delete(t)                            },                            o = e.get(t) || r.get(t) || i.get(t);                          if (200 !== t.status || !t.originalResponseText) return void n();                          try {                            for (let n of function(t) {                                let e = JSON.parse(t);                                if (Array.isArray(e)) {                                  let t = e[1]?.[5];                                  return Array.isArray(t) ? t.map(tb).filter(I).flatMap(t => {                                    let {                                      threadId: e,                                      oldThreadId: n,                                      parsedMessages: r                                    } = t;                                    return r.map(t => {                                      let {                                        messageId: r,                                        to: i,                                        cc: o,                                        bcc: s,                                        actions: a,                                        rfcID: u,                                        oldMessageId: l                                      } = t, c = tx(a);                                      return c ? {                                        threadId: e,                                        messageId: r,                                        to: i,                                        cc: o,                                        bcc: s,                                        actions: a,                                        rfcID: u,                                        oldMessageId: l,                                        oldThreadId: n,                                        type: c                                      } : null                                    })                                  }).filter(I) : []                                }                                return []                              }(t.originalResponseText))                              if (!o || n.messageId.endsWith(o)) {                                if ("FIRST_DRAFT_SAVE" === n.type || "DRAFT_SAVE" === n.type) {                                  tO({                                    draftID: o,                                    type: "emailDraftReceived",                                    rfcID: n.rfcID,                                    threadID: n.threadId,                                    messageID: n.messageId,                                    oldMessageID: n.oldMessageId,                                    oldThreadID: n.oldThreadId                                  }), e.delete(t), r.delete(t), i.delete(t);                                  return                                } else if ("SEND" === n.type) {                                  tO({                                    draftID: o,                                    type: "emailSent",                                    rfcID: n.rfcID,                                    threadID: n.threadId,                                    messageID: n.messageId,                                    oldMessageID: n.oldMessageId,                                    oldThreadID: n.oldThreadId                                  }), e.delete(t), r.delete(t), i.delete(t);                                  return                                }                              }                          } catch (t) {                            v.eventSdkPassive("connection.requestResponseParsingFailed", {                              responseParseError: t                            })                          }                          let s = JSON.parse(t.originalResponseText);                          if (i.has(t)) {                            let t = s[2] && s[2][6] && s[2][6][0] && s[2][6][0][1];                            if (t) {                              let e = t[3] && t[3][7] && t[3][7][1],                                n = e && e[5] && e[5][0];                              e && n ? tO({                                draftID: o,                                type: "emailDraftReceived",                                rfcID: n[14],                                threadID: e[4].split("|")[0],                                messageID: n[1],                                oldMessageID: n[56],                                oldThreadID: e[20]                              }) : v.error(Error("Could not parse draft save"))                            } else {                              v.eventSdkPassive("old compose draft id handling hit");                              let t = s[2] && s[2][6] && s[2][6][1] && s[2][6][1][1];                              if (t) {                                let e = t[3] && t[3][1] && t[3][1][1];                                e && tO({                                  draftID: o,                                  type: "emailDraftReceived",                                  rfcID: e[14],                                  messageID: e[1],                                  oldMessageID: e[48] ? new(p())(e[48]).toString(16) : e[56],                                  syncThreadID: t[1]                                })                              }                            }                          } else {                            let r = s[2]?.[6];                            if (!r) return void n();                            let i = r.find(t => t[1]?.[3]?.[7]?.[1]?.[5]?.[0]?.[14] && t[1][3][7][1][5].find(t => h()(t[1], o)));                            if (!i) {                              if (e.has(t)) {                                let t = r.filter(t => t[1]?.[3]?.[5]?.[3]);                                t.length > 0 ? tO({                                  draftID: o,                                  type: "emailSent",                                  threadID: t[0][1][1] ? t[0][1][1].replace(/\|.*$/, "") : void 0,                                  messageID: t[0][1][3]?.[5]?.[5]?.[0] || t[0][1][3][5][3]?.[0]                                }) : n()                              } else n();                              return                            }                            let a = i[1]?.[3]?.[7]?.[1],                              u = a[5].find(t => t[1].includes(o));                            if (!u) return void n();                            let l = e.has(t);                            Array.isArray(u[11]) ? l && u[11].indexOf("^r") >= 0 && v.error(Error('sendUpdate[11] unexpectedly contained "^r"')) : v.error(Error("sendUpdate[11] was not an array")), l && void 0 !== u[22] && 3 !== u[22] && v.error(Error("sendUpdate[22] was not expected value"), {                              value: u[22]                            });                            let c = a[4] ? a[4].replace(/\|.*$/, "") : void 0;                            tO({                              draftID: o,                              type: l ? "emailSent" : "emailDraftReceived",                              rfcID: u[14],                              messageID: u[1],                              oldMessageID: u[48] ? new(p())(u[48]).toString(16) : u[56],                              threadID: c,                              oldThreadID: null != a[18] ? new(p())(a[18]).toString(16) : a[20]                            })                          }                          e.delete(t), r.delete(t), i.delete(t)                        }                      }                    })                  }                }                r.push({                  isRelevantTo: t => !!t.params.search && "tl" === t.params.view,                  responseTextChanger: async (t, e) => e,                  originalResponseTextLogger(t) {                    if (200 === t.status) {                      var e;                      e = t.originalResponseText, $(M.rq(e))                    }                  }                }), r.push({                  isRelevantTo: t => "cv" === t.params.view,                  originalResponseTextLogger(t) {                    200 === t.status && ti(M.St(t.originalResponseText))                  }                }), n.push({                  isRelevantTo: function(t) {                    return /sync(?:\/u\/\d+)?\/i\/bv/.test(t.url)                  },                  originalResponseTextLogger(t) {                    200 === t.status && ti((function(t) {                      let e = JSON.parse(t);                      if (Array.isArray(e)) try {                        var n = e;                        let t = n && n[2];                        return t ? t.map((t, e) => {                          let r = t[0];                          return r ? {                            subject: r[0],                            snippet: r[1],                            syncThreadID: r[3],                            oldGmailThreadID: null != r[17] ? new(p())(r[17]).toString(16) : r[19],                            rawResponse: t,                            extraMetaData: {                              snippet: n[14] && n[14][0] && n[14][0][e] || "",                              syncMessageData: r[4].map(t => ({                                syncMessageID: t[0],                                oldMessageID: t[55],                                date: +t[6]                              }))                            }                          } : null                        }).filter(I) : []                      } catch (t) {                        return []                      }                      let r = e && e[3];                      return r ? r.map((t, n) => {                        let r = t[1];                        return r ? {                          subject: r[1],                          snippet: r[2],                          syncThreadID: r[4],                          oldGmailThreadID: null != r[18] ? new(p())(r[18]).toString(16) : r[20],                          rawResponse: t,                          extraMetaData: {                            snippet: e[15] && e[15][1] && e[15][1][n] || "",                            syncMessageData: r[5].map(t => ({                              syncMessageID: t[1],                              oldMessageID: t[56],                              date: +t[7]                            }))                          }                        } : null                      }).filter(I) : []                    })(t.originalResponseText).map(t => ({                      syncThreadID: t.syncThreadID,                      threadID: t.oldGmailThreadID,                      messages: t.extraMetaData.syncMessageData.map(t => ({                        date: t.date,                        recipients: t.recipients                      }))                    })))                  }                }), n.push({                  isRelevantTo: function(t) {                    return /sync(?:\/u\/\d+)?\/i\/fd/.test(t.url)                  },                  originalResponseTextLogger(t) {                    200 === t.status && ti(J(t.originalResponseText).map(t => ({                      syncThreadID: t.syncThreadID,                      threadID: t.oldGmailThreadID,                      messages: t.extraMetaData.syncMessageData.map(t => ({                        date: t.date,                        recipients: t.recipients                      }))                    })))                  }                });                {                  let t, e, r, i = Object.create(null);                  document.addEventListener("inboxSDKregisterSuggestionsModifier", function(t) {                    let {                      detail: e                    } = t;                    i[e.providerID] = {                      position: Object.keys(i).length                    }                  }), document.addEventListener("inboxSDKprovideSuggestions", function(n) {                    let {                      detail: o                    } = n;                    if (o.query === t) {                      let n = i[o.providerID];                      if (!n) throw Error("provider does not exist for providerID");                      if (null == e) throw Error("tried to modified a null suggestionModifications");                      if (e[n.position] = o.suggestions, e.filter(Boolean).length === Object.keys(i).length) {                        if (null == r) throw Error("tried to resolve a null currentQueryDefer");                        r.resolve(s()(e)), r = t = e = null                      }                    }                  }), n.push({                    isRelevantTo: t => Object.keys(i).length > 0 && !!t.url.match(/^\/cloudsearch\/request\?/) && "gmail" == t.params.client && "gmail" == t.params.gs_ri,                    originalSendBodyLogger(n, i) {                      let o = D.parse(i);                      if (!o.request) return;                      let s = JSON.parse(o.request)[2];                      s && (t = s, r && r.resolve(), r = n._defer = ta(), e = [], tO({                        type: "suggestionsRequest",                        query: t                      }))                    },                    async responseTextChanger(e, n) {                      if (e._defer && 200 === e.status) {                        let r = await e._defer.promise;                        if (r) {                          let e;                          try {                            e = (0, tu.A)(n, r)                          } catch (e) {                            throw v.eventSdkPassive("suggestionsModified.error", {                              query: t,                              originalResponseText: n,                              error: e instanceof Error && e.message                            }, !0), e                          }                          return e                        }                      }                      return n                    }                  })                } {                  let t, e = [];                  document.addEventListener("inboxSDKcreateCustomSearchTerm", function(t) {                    e.push(t.detail.term)                  }), document.addEventListener("inboxSDKsearchReplacementReady", function(e) {                    t.query === e.detail.query && t.newQuery.resolve(e.detail.newQuery)                  }), r.push({                    isRelevantTo: function(n) {                      let r, i = n.params;                      return !!("POST" === n.method && i.search && "tl" === i.view && n.url.match(/^\?/)) && !!i.q && !!(r = c()(e, ts(i.q))[0]) && (t && t.query === i.q && t.start != i.start ? (n._queryReplacement = t, t.start = i.start) : (t && t.newQuery.resolve(t.query), t = n._queryReplacement = {                        term: r,                        query: i.q,                        start: i.start,                        newQuery: ta()                      }, tO({                        type: "searchQueryForReplacement",                        term: r,                        query: i.q                      })), !0)                    },                    requestChanger: function(t, e) {                      return t._queryReplacement.newQuery.promise.then(function(n) {                        let r = i()(t.params);                        return r.q = n, {                          method: e.method,                          url: "?" + (0, D.stringify)(r),                          body: e.body                        }                      })                    }                  }), n.push({                    isRelevantTo: function(t) {                      return "POST" === t.method && /sync(?:\/u\/\d+)?\/i\/bv/.test(t.url)                    },                    requestChanger: function(n, r) {                      let i, o, s, a, u = JSON.parse(r.body),                        l = !1;                      return (Array.isArray(u) ? (l = !0, s = (o = u[0])[3], a = o[9]) : (s = (o = u[1])[4], a = o[10]), 79 === o[+!l] && "string" == typeof s && (i = c()(e, ts(s))[0])) ? (t && t.query === s && t.start != a ? (n._queryReplacement = t, t.start = a) : (t && t.newQuery.resolve(t.query), t = n._queryReplacement = {                        term: i,                        query: s,                        start: a,                        newQuery: ta()                      }, tO({                        type: "searchQueryForReplacement",                        term: i,                        query: s                      })), n._queryReplacement.newQuery.promise.then(function(t) {                        return l ? u[0][3] = t : u[1][4] = t, {                          method: r.method,                          url: r.url,                          body: JSON.stringify(u)                        }                      })) : Promise.resolve(r)                    }                  })                } {                  let t, e = [];                  document.addEventListener("inboxSDKcustomListRegisterQuery", t => {                    e.push(t.detail.query)                  }), document.addEventListener("inboxSDKcustomListNewQuery", e => {                    if (t.query === e.detail.query && t.start === e.detail.start) {                      let {                        newQuery: n,                        newStart: r                      } = e.detail;                      t.newRequestParams.resolve({                        query: n,                        start: r                      })                    }                  }), document.addEventListener("inboxSDKcustomListResults", e => {                    t.query === e.detail.query && t.newResults.resolve(e.detail.newResults)                  }), r.push({                    isRelevantTo: function(n) {                      let r = n.params;                      return !!("POST" === n.method && r.search && "tl" === r.view && n.url.match(/^\?/) && r.q && !r.act && u()(e, t => t === r.q)) && (t && (t.newRequestParams.resolve({                        query: t.query,                        start: t.start                      }), t.newResults.resolve(null)), tO({                        type: "searchForReplacement",                        query: (t = n._customListJob = {                          query: r.q,                          start: +r.start,                          newRequestParams: ta(),                          newResults: ta()                        }).query,                        start: t.start                      }), !0)                    },                    requestChanger: function(t, e) {                      return t._customListJob.newRequestParams.promise.then(n => {                        let {                          query: r,                          start: o                        } = n, s = i()(t.params);                        return s.q = r, s.start = o, {                          method: e.method,                          url: "?" + (0, D.stringify)(s),                          body: e.body                        }                      })                    },                    responseTextChanger: function(t, e) {                      return tO({                        type: "searchResultsResponse",                        query: t._customListJob.query,                        start: t._customListJob.start,                        response: e                      }), t._customListJob.newResults.promise.then(t => null === t ? e : t)                    }                  }), n.push({                    isRelevantTo: function(e) {                      return !!/sync(?:\/u\/\d+)?\/i\/bv/.test(e.url) && (t && (t.newRequestParams.resolve({                        query: t.query,                        start: t.start                      }), t.newResults.resolve(null)), !0)                    },                    requestChanger: async function(n, r) {                      if (r.body) {                        let i = JSON.parse(r.body),                          o = Array.isArray(i),                          s = (o ? i && i[0] && i[0][3] : i && i[1] && i[1][4]) || "";                        if (u()(e, t => t === s)) return tO({                          type: "searchForReplacement",                          query: (t = n._customListJob = {                            query: s,                            start: o ? i[0][9] : i[1][10],                            newRequestParams: ta(),                            newResults: ta()                          }).query,                          start: t.start                        }), n._customListJob.newRequestParams.promise.then(t => {                          let {                            query: e,                            start: n                          } = t;                          return o ? (i[0][3] = e, i[0][9] = n) : (i[1][4] = e, i[1][10] = n), {                            method: r.method,                            url: r.url,                            body: JSON.stringify(i)                          }                        })                      }                      return r                    },                    responseTextChanger: async function(t, e) {                      return t._customListJob ? (tO({                        type: "searchResultsResponse",                        query: t._customListJob.query,                        start: t._customListJob.start,                        response: e                      }), t._customListJob.newResults.promise.then(t => null === t ? e : t)) : e                    }                  })                } {                  let t = t => {                    document.head.setAttribute("data-inboxsdk-btai-header", t), tO({                      type: "btaiHeaderReceived"                    })                  };                  n.push({                    isRelevantTo: t => /sync(?:\/u\/\d+)?\//.test(t.url) && !document.head.hasAttribute("data-inboxsdk-btai-header"),                    originalSendBodyLogger(e) {                      e.headers["X-Gmail-BTAI"] && t(e.headers["X-Gmail-BTAI"])                    }                  });                  let e = t => {                    t !== document.head.getAttribute("data-inboxsdk-xsrf-token") && (document.head.setAttribute("data-inboxsdk-xsrf-token", t), tO({                      type: "xsrfTokenHeaderReceived"                    }))                  };                  n.push({                    isRelevantTo: t => /sync(?:\/u\/\d+)?\//.test(t.url),                    originalSendBodyLogger(t) {                      t.headers["X-Framework-Xsrf-Token"] && e(t.headers["X-Framework-Xsrf-Token"])                    }                  })                } {                  let t = "AIzaSyBm7aDMG9actsWSlx-MvrYsepwdnLgz69I";                  document.addEventListener("inboxSDKgetGoogleRequestHeaders", () => {                    let e = {                      authorization: window.gapi.auth.getAuthHeaderValueForFirstParty([]),                      "x-goog-api-key": t                    };                    document.head.setAttribute("data-inboxsdk-google-headers", JSON.stringify(e))                  }), n.push({                    isRelevantTo: t => !!t.url.startsWith("https://") && new URL(t.url).hostname.endsWith(".google.com"),                    originalSendBodyLogger(e) {                      e.headers["X-Goog-Api-Key"] && (t = e.headers["X-Goog-Api-Key"])                    }                  })                }              }(window, t)          }
External services involved in the event upload
    • pubsub.googleapis.com

    Receives the InboxSDK event batch for the mailfoogae Pub/Sub topic.

    • api.inboxsdk.com

    Provides the OAuth token used before the Pub/Sub publish request.

Updated 30 September 2026ejgmneenioanldgngdomlfnbcbffmchf