Skip to content

fix(analytics): keep MCP API keys out of PostHog session replay - #236

Open
0xenzyme wants to merge 1 commit into
every-app:mainfrom
0xenzyme:fix/api-key-session-replay-mask
Open

fix(analytics): keep MCP API keys out of PostHog session replay#236
0xenzyme wants to merge 1 commit into
every-app:mainfrom
0xenzyme:fix/api-key-session-replay-mask

Conversation

@0xenzyme

Copy link
Copy Markdown
Contributor

Summary

  • Mask the one-time plaintext MCP API key reveal in Settings (data-ph-mask / ph-mask) so PostHog session replay cannot capture it from the DOM.
  • Sanitize captured network requests: drop request/response bodies for Better Auth /api/auth/api-key* routes, and redact full oseo_… keys elsewhere.
  • Fixes New API key can be captured by session replay #233.

Test plan

  • pnpm test -- src/client/lib/posthog-sanitize.test.ts
  • In a hosted (or PostHog-enabled) build, create an API key in Settings and confirm the reveal still works for the user
  • Confirm a session recording of that create flow does not include the plaintext key in the DOM or network payload
- Mask the one-time plaintext key reveal in Settings
- Strip Better Auth api-key network bodies from replay captures
- Redact full oseo_ keys that appear in other captured payloads

@Abhirup0 Abhirup0 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @0xenzyme, thanks for putting this together!

The approach looks really solid to me. Adding both data-ph-mask and .ph-mask to the code block is great, and dropping the request/response bodies entirely for the Better Auth API key endpoints is much safer than just relying on regex pattern matching for the creation payload. Also like that the {16,} regex length check keeps the shortened oseo_abcd display prefixes intact in the UI table.

I just had a couple of small suggestions/thoughts for extra defense-in-depth if you think they're worth adding:

  1. Scrubbing keys from URL query params:
    In sanitizePostHogUrl, we currently handle /oauth-consent and strip email. If someone ever passes an API key as a query param (like ?apiKey=oseo_...), sanitizePostHogCapturedNetworkRequest might still leave it in request.name. Running the regex over url.search or url.toString() as well could be a nice safeguard.

  2. Relative URLs in sanitizePostHogUrl:
    In isApiKeyAuthRequestUrl, you used new URL(name, "https://example.invalid") which handles relative paths cleanly. In sanitizePostHogUrl, new URL(value) without a base will throw on relative URLs (like /api/projects) and jump straight to the catch block returning the raw string. Passing a dummy base URL there too might make it more consistent.

  3. Request headers (minor):
    If PostHog happens to record requestHeaders in your setup, it might be worth making sure authorization or x-api-key headers get scrubbed if they contain oseo_... tokens.

Either way, the core fix is super clean and the test cases cover the main paths nicely. Thanks again for the PR!

oluwaseunmauwedo pushed a commit to oluwaseunmauwedo/open-seo that referenced this pull request Aug 25, 2026
ramonmnavarro-byte pushed a commit to ramonmnavarro-byte/open-seo that referenced this pull request Aug 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants