Skip to content

fix(replay): stop SCRIPT_PLACEHOLDER rendering in shadow roots - #4703

Draft
posthog[bot] wants to merge 2 commits into
mainfrom
posthog-self-driving/fixreplay-stop-rrweb-leaking-template-76eba3
Draft

fix(replay): stop SCRIPT_PLACEHOLDER rendering in shadow roots#4703
posthog[bot] wants to merge 2 commits into
mainfrom
posthog-self-driving/fixreplay-stop-rrweb-leaking-template-76eba3

Conversation

@posthog

@posthog posthog Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Problem

  • Who it hurts: any customer who records a third-party widget (chat launcher, support embed) that lives in a shadow root. Their replays render our internal SCRIPT_PLACEHOLDER text over the real UI. Zero end-user impact on the recorded site itself.
  • Root cause: a recorded <script> is serialized with its text replaced by the SCRIPT_PLACEHOLDER sentinel (snapshot.ts) and rebuilt as <noscript> so it cannot execute (rebuild.ts). Scripting is off in the replay iframe, so <noscript> content renders as visible text.
  • The replayer hides it with a document-scoped noscript { display: none !important; } style (replay/styles/inject-style.ts). That rule never reaches shadow roots, so the placeholder leaks there.
  • Side effect for internal tooling: the leaked text produced high-confidence false-positive scanner findings on posthog.com (its AI chat is an Inkeep widget in a shadow root) for over a month.

Changes

  • Mechanism: rebuild now emits an empty text node for the placeholder, so it cannot render in any context — document or shadow root, full-snapshot or incremental rebuild path.
  • Kept the scriptnoscript mapping, so scripts still cannot execute on replay.
  • Kept the document-scoped noscript { display: none } style — it still hides genuine <noscript> fallback content during replay (the user had JS on, so they never saw it).
  • Shared the sentinel between snapshot.ts (write) and rebuild.ts (read) through one exported constant, so the contract is explicit.
  • Updated the browser integration snapshots: affected <noscript> outputs are now empty. Serialization output is unchanged (the snapshot still stores the sentinel).

Release info Sub-libraries affected

Libraries affected

  • All of them
  • posthog-js (web)
  • posthog-js-lite (web lite)
  • posthog-node
  • posthog-react-native
  • @posthog/react-native-plugin
  • @posthog/react
  • @posthog/ai
  • @posthog/convex
  • @posthog/next
  • @posthog/nextjs-config
  • @posthog/nuxt
  • @posthog/openfeature-node-provider
  • @posthog/openfeature-web-provider
  • @posthog/rollup-plugin
  • @posthog/webpack-plugin
  • @posthog/types
  • @posthog/browser-common

Checklist

  • Tests for new code
  • Accounted for the impact of any changes across different platforms
  • Accounted for backwards compatibility of any changes (no breaking changes!)
  • Took care not to unnecessarily increase the bundle size

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

Autonomy: Fully autonomous

  • Authored by a PostHog self-driving agent (Claude) from an inbox report. No human drove the work, so the PR is left unassigned for the owning team to triage.
  • Testing done in-sandbox (jsdom): added a rebuild unit test asserting a <script> rebuilds as an empty <noscript>; ran the full @posthog/rrweb-snapshot jsdom suites (rebuild, snapshot, utils, css — all pass), plus tsc --noEmit and eslint.
  • Not run here: the integration.test.ts suite launches real Chrome, which cannot start in this sandbox. Its snapshots were updated by mechanical substitution limited to the rebuild-output lines (<noscript>SCRIPT_PLACEHOLDER</noscript><noscript></noscript>); the serialization-output snapshots were left unchanged. Please let CI regenerate/verify these.
  • Considered and rejected: removing the noscript { display: none } style (would expose genuine <noscript> fallback content on replay); rebuilding <script> as a neutralized <script> (loses the execution-safety guarantee of the noscript mapping); fixing only snapshot.ts (would not repair the millions of existing recordings that already carry the sentinel — the playback fix covers both old and new).

Created with PostHog Desktop from this inbox report.

A recorded `<script>` is serialized with its text replaced by the `SCRIPT_PLACEHOLDER` sentinel and rebuilt as `<noscript>` so it cannot execute. Scripting is off in the replay iframe, so `<noscript>` content renders as visible text, and the `noscript { display: none }` replay style is document-scoped — it never reaches shadow roots. So the placeholder leaked over any third-party widget recorded in a shadow root.

Rebuild now emits an empty text node for the placeholder, so it cannot render in any context, on both the full-snapshot and incremental paths. The sentinel is shared between snapshot and rebuild through one constant. The document-scoped style is kept, because it still hides genuine `<noscript>` fallback content during replay.

Generated-By: PostHog Desktop
Task-Id: af10c549-b6bb-48b0-a1ee-8d0171bf5ca5
@posthog

posthog Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

🦔 PostHog Review reviewed this pull request

Found 1 must fix, 1 should fix, 1 consider.

Published 3 findings (view the review).

Resolved comments: 1 fixed, 2 left for you

@github-actions

Copy link
Copy Markdown
Contributor

Replay incident risk check

This diff touches code involved in past incidents. This is a heads-up, not a verdict: read the matched sections of INCIDENTS.md and answer their review questions before merging.

For a judgment on whether this diff has the same failure mode, run the replay-incident-risk skill locally: open a Claude session in the repo root and ask it to review your diff with that skill. Or run node .agents/skills/replay-incident-risk/check.mjs and answer the review questions for each matched class yourself.

Matched 2 past incident pattern(s) (diff vs origin/main):

## rrweb serialization and snapshot correctness [path match]
Serializer bugs corrupt replays silently: no exception, no volume change. In May 2026 a cssText spec quirk silently dropped layout styles for sites using CSS custom properties. Test against framework-generated CSS (Chakra/Panda, Emotion speedy, Tailwind) in a real browser.
  Touched paths:
    - packages/rrweb/rrweb-snapshot/src/rebuild.ts
    - packages/rrweb/rrweb-snapshot/src/snapshot.ts
    - packages/rrweb/rrweb-snapshot/src/utils.ts
    - packages/rrweb/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap
    - packages/rrweb/rrweb-snapshot/test/rebuild.test.ts
  Read: .agents/skills/replay-incident-risk/INCIDENTS.md#class-4-rrweb-serialization-and-snapshot-correctness

## Masking, privacy, and consent [path match]
A masking or consent regression records data customers promised their users we would not store: passwords, PII, opted-out sessions. Nothing throws and no volume moves, so no alert can fire, and recorded data cannot be un-stored. Add a real-browser test asserting the sensitive value is absent from the emitted snapshot bytes.
  Touched paths:
    - packages/rrweb/rrweb-snapshot/src/rebuild.ts
    - packages/rrweb/rrweb-snapshot/src/snapshot.ts
    - packages/rrweb/rrweb-snapshot/src/utils.ts
    - packages/rrweb/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap
    - packages/rrweb/rrweb-snapshot/test/rebuild.test.ts
  Read: .agents/skills/replay-incident-risk/INCIDENTS.md#class-8-masking-privacy-and-consent-proactive-no-incident-yet

This check is advisory. It flags resemblance to past incidents, not correctness.
For a judgment pass on whether this diff has the same failure mode, run the
`replay-incident-risk` skill in a Claude session from the repo root, or answer the
review questions in the matched sections of .agents/skills/replay-incident-risk/INCIDENTS.md yourself.

@github-actions

github-actions Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

Size Change: +3.95 kB (+0.02%)

Total Size: 20.8 MB

📦 View Changed
Filename Size Change
packages/browser/dist/all-external-dependencies.js 379 kB +10 B (0%)
packages/browser/dist/array.full.js 612 kB +10 B (0%)
packages/browser/dist/array.full.no-********.js 665 kB +10 B (0%)
packages/browser/dist/lazy-********.js 202 kB +10 B (0%)
packages/browser/dist/module.full.js 614 kB +10 B (0%)
packages/browser/dist/module.full.no-********.js 668 kB +10 B (0%)
packages/browser/dist/posthog-********.js 202 kB +10 B (0%)
packages/browser/dist/recorder-v2.js 126 kB +10 B (+0.01%)
packages/browser/dist/recorder.js 126 kB +10 B (+0.01%)
packages/browser/dist/rrweb.js 318 kB +64 B (+0.02%)
packages/rrweb/all/dist/rrweb-all.cjs 705 kB +141 B (+0.02%)
packages/rrweb/all/dist/rrweb-all.js 705 kB +141 B (+0.02%)
packages/rrweb/all/dist/rrweb-all.umd.cjs 709 kB +141 B (+0.02%)
packages/rrweb/all/dist/rrweb-all.umd.min.cjs 328 kB +66 B (+0.02%)
packages/rrweb/record/dist/rrweb-record.cjs 234 kB +47 B (+0.02%)
packages/rrweb/record/dist/rrweb-record.js 233 kB +47 B (+0.02%)
packages/rrweb/record/dist/rrweb-record.umd.cjs 234 kB +47 B (+0.02%)
packages/rrweb/record/dist/rrweb-record.umd.min.cjs 107 kB +12 B (+0.01%)
packages/rrweb/replay/dist/rrweb-replay.cjs 476 kB +143 B (+0.03%)
packages/rrweb/replay/dist/rrweb-replay.js 476 kB +143 B (+0.03%)
packages/rrweb/replay/dist/rrweb-replay.umd.cjs 479 kB +143 B (+0.03%)
packages/rrweb/replay/dist/rrweb-replay.umd.min.cjs 225 kB +78 B (+0.03%)
packages/rrweb/rrweb-snapshot/dist/record.cjs 39.1 kB +59 B (+0.15%)
packages/rrweb/rrweb-snapshot/dist/record.js 37.4 kB +45 B (+0.12%)
packages/rrweb/rrweb-snapshot/dist/record.umd.cjs 83.4 kB +164 B (+0.2%)
packages/rrweb/rrweb-snapshot/dist/record.umd.min.cjs 37.5 kB +100 B (+0.27%)
packages/rrweb/rrweb-snapshot/dist/replay.cjs 149 kB +154 B (+0.1%)
packages/rrweb/rrweb-snapshot/dist/replay.js 149 kB +141 B (+0.09%)
packages/rrweb/rrweb-snapshot/dist/replay.umd.cjs 194 kB +259 B (+0.13%)
packages/rrweb/rrweb-snapshot/dist/replay.umd.min.cjs 86.3 kB +172 B (+0.2%)
packages/rrweb/rrweb-snapshot/dist/rrweb-********.cjs 4 kB +55 B (+1.39%)
packages/rrweb/rrweb-snapshot/dist/rrweb-********.js 2.35 kB +30 B (+1.29%)
packages/rrweb/rrweb-snapshot/dist/rrweb-********.umd.cjs 262 kB +399 B (+0.15%)
packages/rrweb/rrweb-snapshot/dist/rrweb-********.umd.min.cjs 109 kB +256 B (+0.23%)
packages/rrweb/rrweb-snapshot/dist/types-********.cjs 37.7 kB +98 B (+0.26%)
packages/rrweb/rrweb-snapshot/dist/types-********.js 0 B -36.5 kB (removed) 🏆
packages/rrweb/rrweb-snapshot/dist/types-********.umd.cjs 39.1 kB +96 B (+0.25%)
packages/rrweb/rrweb-snapshot/dist/types-********.umd.min.cjs 17.4 kB +58 B (+0.33%)
packages/rrweb/rrweb-snapshot/dist/types-C-89hxwI.js 36.6 kB +36.6 kB (new file) 🆕
packages/rrweb/rrweb/dist/rrweb.cjs 689 kB +141 B (+0.02%)
packages/rrweb/rrweb/dist/rrweb.js 689 kB +141 B (+0.02%)
packages/rrweb/rrweb/dist/rrweb.umd.cjs 689 kB +141 B (+0.02%)
packages/rrweb/rrweb/dist/rrweb.umd.min.cjs 318 kB +66 B (+0.02%)
ℹ️ View Unchanged
Filename Size Change
packages/ai/dist/anthropic/index.cjs 41.3 kB 0 B
packages/ai/dist/anthropic/index.mjs 41 kB 0 B
packages/ai/dist/gemini/index.cjs 40.9 kB 0 B
packages/ai/dist/gemini/index.mjs 40.8 kB 0 B
packages/ai/dist/index.cjs 63.4 kB 0 B
packages/ai/dist/index.mjs 63.3 kB 0 B
packages/ai/dist/langchain/index.cjs 42.8 kB 0 B
packages/ai/dist/langchain/index.mjs 42.7 kB 0 B
packages/ai/dist/langchain/middleware/index.cjs 49.5 kB 0 B
packages/ai/dist/langchain/middleware/index.mjs 49.4 kB 0 B
packages/ai/dist/openai-agents/index.cjs 31.8 kB 0 B
packages/ai/dist/openai-agents/index.mjs 31.7 kB 0 B
packages/ai/dist/openai/index.cjs 93.3 kB 0 B
packages/ai/dist/openai/index.mjs 92.9 kB 0 B
packages/ai/dist/otel/index.cjs 18.4 kB 0 B
packages/ai/dist/otel/index.mjs 18.3 kB 0 B
packages/ai/dist/vercel/index.cjs 53.5 kB 0 B
packages/ai/dist/vercel/index.mjs 53.5 kB 0 B
packages/browser-common/dist/client.js 603 B 0 B
packages/browser-common/dist/client.mjs 0 B 0 B 🆕
packages/browser-common/dist/config.js 1.43 kB 0 B
packages/browser-common/dist/config.mjs 223 B 0 B
packages/browser-common/dist/constants.js 1.66 kB 0 B
packages/browser-common/dist/constants.mjs 219 B 0 B
packages/browser-common/dist/disposable.js 1.63 kB 0 B
packages/browser-common/dist/disposable.mjs 386 B 0 B
packages/browser-common/dist/extension-runtime.js 3.07 kB 0 B
packages/browser-common/dist/extension-runtime.mjs 1.83 kB 0 B
packages/browser-common/dist/extension.js 603 B 0 B
packages/browser-common/dist/extension.mjs 0 B 0 B 🆕
packages/browser-common/dist/index.js 3.08 kB 0 B
packages/browser-common/dist/index.mjs 170 B 0 B
packages/browser-common/dist/persistence.js 603 B 0 B
packages/browser-common/dist/persistence.mjs 0 B 0 B 🆕
packages/browser-common/dist/pubsub.js 2.53 kB 0 B
packages/browser-common/dist/pubsub.mjs 1.35 kB 0 B
packages/browser-common/dist/token.js 603 B 0 B
packages/browser-common/dist/token.mjs 0 B 0 B 🆕
packages/browser-common/dist/types/compression.js 1.28 kB 0 B
packages/browser-common/dist/types/compression.mjs 93 B 0 B
packages/browser-common/dist/types/index.js 4.11 kB 0 B
packages/browser-common/dist/types/index.mjs 144 B 0 B
packages/browser-common/dist/types/network-recording.js 603 B 0 B
packages/browser-common/dist/types/network-recording.mjs 0 B 0 B 🆕
packages/browser-common/dist/types/remote-config.js 603 B 0 B
packages/browser-common/dist/types/remote-config.mjs 0 B 0 B 🆕
packages/browser-common/dist/types/surveys.js 4.55 kB 0 B
packages/browser-common/dist/types/surveys.mjs 2.17 kB 0 B
packages/browser-common/dist/utils/array-at-********.js 628 B 0 B
packages/browser-common/dist/utils/array-at-********.mjs 425 B 0 B
packages/browser-common/dist/utils/autocapture-utils.js 24.2 kB 0 B
packages/browser-common/dist/utils/autocapture-utils.mjs 18.6 kB 0 B
packages/browser-common/dist/utils/blocked-uas.js 2.1 kB 0 B
packages/browser-common/dist/utils/blocked-uas.mjs 598 B 0 B
packages/browser-common/dist/utils/cookie-utils.js 1.89 kB 0 B
packages/browser-common/dist/utils/cookie-utils.mjs 673 B 0 B
packages/browser-common/dist/utils/device-model-utils.js 1.98 kB 0 B
packages/browser-common/dist/utils/device-model-utils.mjs 678 B 0 B
packages/browser-common/dist/utils/element-utils.js 2.46 kB 0 B
packages/browser-common/dist/utils/element-utils.mjs 804 B 0 B
packages/browser-common/dist/utils/elements-chain-utils.js 2.77 kB 0 B
packages/browser-common/dist/utils/elements-chain-utils.mjs 1.23 kB 0 B
packages/browser-common/dist/utils/encode-utils.js 1.4 kB 0 B
packages/browser-common/dist/utils/encode-utils.mjs 205 B 0 B
packages/browser-common/dist/utils/event-utils.js 15.7 kB 0 B
packages/browser-common/dist/utils/event-utils.mjs 10 kB 0 B
packages/browser-common/dist/utils/general-utils.js 7.31 kB 0 B
packages/browser-common/dist/utils/general-utils.mjs 4.49 kB 0 B
packages/browser-common/dist/utils/globals.js 2.78 kB 0 B
packages/browser-common/dist/utils/globals.mjs 860 B 0 B
packages/browser-common/dist/utils/logger.js 3.4 kB 0 B
packages/browser-common/dist/utils/logger.mjs 1.61 kB 0 B
packages/browser-common/dist/utils/matcher-utils.js 2.85 kB 0 B
packages/browser-common/dist/utils/matcher-utils.mjs 1.33 kB 0 B
packages/browser-common/dist/utils/promise-utils.js 1.36 kB 0 B
packages/browser-common/dist/utils/promise-utils.mjs 169 B 0 B
packages/browser-common/dist/utils/property-utils.js 3.53 kB 0 B
packages/browser-common/dist/utils/property-utils.mjs 1.6 kB 0 B
packages/browser-common/dist/utils/prototype-utils.js 3.51 kB 0 B
packages/browser-common/dist/utils/prototype-utils.mjs 1.86 kB 0 B
packages/browser-common/dist/utils/regex-utils.js 1.45 kB 0 B
packages/browser-common/dist/utils/regex-utils.mjs 113 B 0 B
packages/browser-common/dist/utils/request-utils.js 6.73 kB 0 B
packages/browser-common/dist/utils/request-utils.mjs 4.19 kB 0 B
packages/browser-common/dist/utils/simple-event-emitter.js 1.76 kB 0 B
packages/browser-common/dist/utils/simple-event-emitter.mjs 553 B 0 B
packages/browser-common/dist/utils/stylesheet-loader.js 2.13 kB 0 B
packages/browser-common/dist/utils/stylesheet-loader.mjs 823 B 0 B
packages/browser-common/dist/utils/type-utils.js 1.59 kB 0 B
packages/browser-common/dist/utils/type-utils.mjs 267 B 0 B
packages/browser-common/dist/utils/url-targeting-utils.js 2.35 kB 0 B
packages/browser-common/dist/utils/url-targeting-utils.mjs 863 B 0 B
packages/browser-common/dist/utils/uuidv7.js 6.66 kB 0 B
packages/browser-common/dist/utils/uuidv7.mjs 5.18 kB 0 B
packages/browser-next/dist/analytics-********.js 1.58 kB 0 B
packages/browser-next/dist/analytics-********.mjs 219 B 0 B
packages/browser-next/dist/analytics-options.js 603 B 0 B
packages/browser-next/dist/analytics-options.mjs 0 B 0 B 🆕
packages/browser-next/dist/analytics.js 6.52 kB 0 B
packages/browser-next/dist/analytics.mjs 5.15 kB 0 B
packages/browser-next/dist/bot-filter.js 2.28 kB 0 B
packages/browser-next/dist/bot-filter.mjs 1.09 kB 0 B
packages/browser-next/dist/capture-v1.js 27.7 kB 0 B
packages/browser-next/dist/capture-v1.mjs 25.3 kB 0 B
packages/browser-next/dist/core.js 1.59 kB 0 B
packages/browser-next/dist/core.mjs 194 B 0 B
packages/browser-next/dist/extensions/registry.js 3.32 kB 0 B
packages/browser-next/dist/extensions/registry.mjs 2.11 kB 0 B
packages/browser-next/dist/id.js 2.15 kB 0 B
packages/browser-next/dist/id.mjs 983 B 0 B
packages/browser-next/dist/index.js 3.38 kB 0 B
packages/browser-next/dist/index.mjs 1.19 kB 0 B
packages/browser-next/dist/lane.js 18 kB 0 B
packages/browser-next/dist/lane.mjs 16.9 kB 0 B
packages/browser-next/dist/logger.js 1.77 kB 0 B
packages/browser-next/dist/logger.mjs 581 B 0 B
packages/browser-next/dist/posthog.js 33.1 kB 0 B
packages/browser-next/dist/posthog.mjs 30.9 kB 0 B
packages/browser-next/dist/rate-limiter.js 2.79 kB 0 B
packages/browser-next/dist/rate-limiter.mjs 1.58 kB 0 B
packages/browser-next/dist/request.js 4.52 kB 0 B
packages/browser-next/dist/request.mjs 3.21 kB 0 B
packages/browser-next/dist/state.js 24.8 kB 0 B
packages/browser-next/dist/state.mjs 23.2 kB 0 B
packages/browser-next/dist/types.js 603 B 0 B
packages/browser-next/dist/types.mjs 0 B 0 B 🆕
packages/browser-next/dist/version.js 1.21 kB 0 B
packages/browser-next/dist/version.mjs 45 B 0 B
packages/browser/dist/array.full.es5.js 481 kB 0 B
packages/browser/dist/array.js 270 kB 0 B
packages/browser/dist/array.no-********.js 305 kB 0 B
packages/browser/dist/conversations.js 68.2 kB 0 B
packages/browser/dist/crisp-chat-integration.js 2.03 kB 0 B
packages/browser/dist/customizations.full.js 15.9 kB 0 B
packages/browser/dist/customizations.js 15.8 kB 0 B
packages/browser/dist/dead-clicks-autocapture.js 18.3 kB 0 B
packages/browser/dist/default-extensions.js 268 kB 0 B
packages/browser/dist/element-inference.js 5.62 kB 0 B
packages/browser/dist/exception-autocapture.js 13.6 kB 0 B
packages/browser/dist/extension-bundles.js 152 kB 0 B
packages/browser/dist/external-scripts-loader.js 3.6 kB 0 B
packages/browser/dist/intercom-integration.js 2.08 kB 0 B
packages/browser/dist/logs.js 5.83 kB 0 B
packages/browser/dist/main.js 274 kB 0 B
packages/browser/dist/module.js 274 kB 0 B
packages/browser/dist/module.no-********.js 309 kB 0 B
packages/browser/dist/module.slim.js 133 kB 0 B
packages/browser/dist/module.slim.no-********.js 144 kB 0 B
packages/browser/dist/product-tours-preview.js 82.4 kB 0 B
packages/browser/dist/product-tours.js 124 kB 0 B
packages/browser/dist/rrweb-plugin-console-record.js 7.05 kB 0 B
packages/browser/dist/rrweb-types.js 2.33 kB 0 B
packages/browser/dist/surveys-preview.js 81.5 kB 0 B
packages/browser/dist/surveys.js 103 kB 0 B
packages/browser/dist/tracing-headers.js 3.76 kB 0 B
packages/browser/dist/web-vitals-soft-navs.js 9.9 kB 0 B
packages/browser/dist/web-vitals-with-attribution-soft-navs.js 25.1 kB 0 B
packages/browser/dist/web-vitals-with-attribution.js 18.4 kB 0 B
packages/browser/dist/web-vitals.js 6.91 kB 0 B
packages/browser/react/dist/esm/index.js 22.5 kB 0 B
packages/browser/react/dist/esm/slim/index.js 18.9 kB 0 B
packages/browser/react/dist/esm/surveys/index.js 4.75 kB 0 B
packages/browser/react/dist/umd/index.js 25.9 kB 0 B
packages/browser/react/dist/umd/slim/index.js 21.8 kB 0 B
packages/browser/react/dist/umd/surveys/index.js 5.52 kB 0 B
packages/convex/dist/client/feature-flags/crypto.js 76 B 0 B
packages/convex/dist/client/feature-flags/evaluator.js 14.9 kB 0 B
packages/convex/dist/client/feature-flags/index.js 196 B 0 B
packages/convex/dist/client/feature-flags/match-********.js 5.08 kB 0 B
packages/convex/dist/client/feature-flags/types.js 44 B 0 B
packages/convex/dist/client/index.js 14.8 kB 0 B
packages/convex/dist/component/_generated/api.js 712 B 0 B
packages/convex/dist/component/_generated/component.js 212 B 0 B
packages/convex/dist/component/_generated/dataModel.js 230 B 0 B
packages/convex/dist/component/_generated/server.js 3.74 kB 0 B
packages/convex/dist/component/convex.config.js 1.66 kB 0 B
packages/convex/dist/component/crons.js 969 B 0 B
packages/convex/dist/component/lib.js 24.8 kB 0 B
packages/convex/dist/component/schema.js 1.17 kB 0 B
packages/convex/dist/component/version.js 67 B 0 B
packages/core/dist/cookie.js 5.34 kB 0 B
packages/core/dist/cookie.mjs 3.12 kB 0 B
packages/core/dist/error-tracking/chunk-ids.js 2.54 kB 0 B
packages/core/dist/error-tracking/chunk-ids.mjs 1.31 kB 0 B
packages/core/dist/error-tracking/coercers/dom-exception-coercer.js 2.3 kB 0 B
packages/core/dist/error-tracking/coercers/dom-exception-coercer.mjs 993 B 0 B
packages/core/dist/error-tracking/coercers/error-coercer.js 2.13 kB 0 B
packages/core/dist/error-tracking/coercers/error-coercer.mjs 888 B 0 B
packages/core/dist/error-tracking/coercers/error-event-coercer.js 2.37 kB 0 B
packages/core/dist/error-tracking/coercers/error-event-coercer.mjs 1.07 kB 0 B
packages/core/dist/error-tracking/coercers/event-coercer.js 1.82 kB 0 B
packages/core/dist/error-tracking/coercers/event-coercer.mjs 548 B 0 B
packages/core/dist/error-tracking/coercers/index.js 6.79 kB 0 B
packages/core/dist/error-tracking/coercers/index.mjs 326 B 0 B
packages/core/dist/error-tracking/coercers/object-coercer.js 4.04 kB 0 B
packages/core/dist/error-tracking/coercers/object-coercer.mjs 2.53 kB 0 B
packages/core/dist/error-tracking/coercers/primitive-coercer.js 1.67 kB 0 B
packages/core/dist/error-tracking/coercers/primitive-coercer.mjs 419 B 0 B
packages/core/dist/error-tracking/coercers/promise-rejection-event.js 2.59 kB 0 B
packages/core/dist/error-tracking/coercers/promise-rejection-event.mjs 1.25 kB 0 B
packages/core/dist/error-tracking/coercers/string-coercer.js 2.01 kB 0 B
packages/core/dist/error-tracking/coercers/string-coercer.mjs 820 B 0 B
packages/core/dist/error-tracking/coercers/utils.js 2.06 kB 0 B
packages/core/dist/error-tracking/coercers/utils.mjs 716 B 0 B
packages/core/dist/error-tracking/error-properties-builder.js 5.56 kB 0 B
packages/core/dist/error-tracking/error-properties-builder.mjs 4.23 kB 0 B
packages/core/dist/error-tracking/exception-steps.js 6.01 kB 0 B
packages/core/dist/error-tracking/exception-steps.mjs 3.84 kB 0 B
packages/core/dist/error-tracking/index.js 5.32 kB 0 B
packages/core/dist/error-tracking/index.mjs 222 B 0 B
packages/core/dist/error-tracking/parsers/base.js 2 kB 0 B
packages/core/dist/error-tracking/parsers/base.mjs 627 B 0 B
packages/core/dist/error-tracking/parsers/chrome.js 2.73 kB 0 B
packages/core/dist/error-tracking/parsers/chrome.mjs 1.32 kB 0 B
packages/core/dist/error-tracking/parsers/gecko.js 2.47 kB 0 B
packages/core/dist/error-tracking/parsers/gecko.mjs 1.13 kB 0 B
packages/core/dist/error-tracking/parsers/index.js 4.75 kB 0 B
packages/core/dist/error-tracking/parsers/index.mjs 2.1 kB 0 B
packages/core/dist/error-tracking/parsers/node.js 4.21 kB 0 B
packages/core/dist/error-tracking/parsers/node.mjs 2.95 kB 0 B
packages/core/dist/error-tracking/parsers/opera.js 2.26 kB 0 B
packages/core/dist/error-tracking/parsers/opera.mjs 746 B 0 B
packages/core/dist/error-tracking/parsers/safari.js 1.88 kB 0 B
packages/core/dist/error-tracking/parsers/safari.mjs 574 B 0 B
packages/core/dist/error-tracking/parsers/winjs.js 1.72 kB 0 B
packages/core/dist/error-tracking/parsers/winjs.mjs 426 B 0 B
packages/core/dist/error-tracking/release.js 1.42 kB 0 B
packages/core/dist/error-tracking/release.mjs 203 B 0 B
packages/core/dist/error-tracking/types.js 1.33 kB 0 B
packages/core/dist/error-tracking/types.mjs 131 B 0 B
packages/core/dist/error-tracking/utils.js 1.8 kB 0 B
packages/core/dist/error-tracking/utils.mjs 604 B 0 B
packages/core/dist/eventemitter.js 1.78 kB 0 B
packages/core/dist/eventemitter.mjs 571 B 0 B
packages/core/dist/featureFlagLocalEvaluation.js 22.1 kB 0 B
packages/core/dist/featureFlagLocalEvaluation.mjs 19.6 kB 0 B
packages/core/dist/featureFlagUtils.js 8.52 kB 0 B
packages/core/dist/featureFlagUtils.mjs 5.48 kB 0 B
packages/core/dist/gzip.js 5.79 kB 0 B
packages/core/dist/gzip.mjs 3.87 kB 0 B
packages/core/dist/index.js 23.2 kB 0 B
packages/core/dist/index.mjs 2.47 kB 0 B
packages/core/dist/logs/index.js 10.8 kB 0 B
packages/core/dist/logs/index.mjs 9.17 kB 0 B
packages/core/dist/logs/logs-utils.js 12.4 kB 0 B
packages/core/dist/logs/logs-utils.mjs 9.71 kB 0 B
packages/core/dist/logs/types.js 603 B 0 B
packages/core/dist/logs/types.mjs 0 B 0 B 🆕
packages/core/dist/metrics/config.js 1.95 kB 0 B
packages/core/dist/metrics/config.mjs 735 B 0 B
packages/core/dist/metrics/index.js 14.4 kB 0 B
packages/core/dist/metrics/index.mjs 12 kB 0 B
packages/core/dist/metrics/metrics-utils.js 3.86 kB 0 B
packages/core/dist/metrics/metrics-utils.mjs 1.97 kB 0 B
packages/core/dist/metrics/types.js 603 B 0 B
packages/core/dist/metrics/types.mjs 0 B 0 B 🆕
packages/core/dist/posthog-core-stateless.js 46.9 kB 0 B
packages/core/dist/posthog-core-stateless.mjs 43.6 kB 0 B
packages/core/dist/posthog-core.js 49.5 kB 0 B
packages/core/dist/posthog-core.mjs 43.9 kB 0 B
packages/core/dist/surveys/activation.js 2.2 kB 0 B
packages/core/dist/surveys/activation.mjs 572 B 0 B
packages/core/dist/surveys/events.js 4.27 kB 0 B
packages/core/dist/surveys/events.mjs 2.05 kB 0 B
packages/core/dist/surveys/index.js 6.54 kB 0 B
packages/core/dist/surveys/index.mjs 1.4 kB 0 B
packages/core/dist/surveys/keys.js 1.7 kB 0 B
packages/core/dist/surveys/keys.mjs 350 B 0 B
packages/core/dist/surveys/property-********.js 3.69 kB 0 B
packages/core/dist/surveys/property-********.mjs 2.14 kB 0 B
packages/core/dist/surveys/translations.js 9.09 kB 0 B
packages/core/dist/surveys/translations.mjs 6.83 kB 0 B
packages/core/dist/surveys/validation.js 3.06 kB 0 B
packages/core/dist/surveys/validation.mjs 1.51 kB 0 B
packages/core/dist/testing/index.js 2.93 kB 0 B
packages/core/dist/testing/index.mjs 79 B 0 B
packages/core/dist/testing/PostHogCoreTestClient.js 3.24 kB 0 B
packages/core/dist/testing/PostHogCoreTestClient.mjs 1.83 kB 0 B
packages/core/dist/testing/test-utils.js 2.83 kB 0 B
packages/core/dist/testing/test-utils.mjs 1.15 kB 0 B
packages/core/dist/tracing-headers.js 3.38 kB 0 B
packages/core/dist/tracing-headers.mjs 2.08 kB 0 B
packages/core/dist/types.js 8.35 kB 0 B
packages/core/dist/types.mjs 5.23 kB 0 B
packages/core/dist/utils/bot-detection.js 3.28 kB 0 B
packages/core/dist/utils/bot-detection.mjs 1.96 kB 0 B
packages/core/dist/utils/browser-utils.js 1.48 kB 0 B
packages/core/dist/utils/browser-utils.mjs 182 B 0 B
packages/core/dist/utils/bucketed-rate-limiter.js 4.23 kB 0 B
packages/core/dist/utils/bucketed-rate-limiter.mjs 2.22 kB 0 B
packages/core/dist/utils/index.js 16.6 kB 0 B
packages/core/dist/utils/index.mjs 3.36 kB 0 B
packages/core/dist/utils/json-utils.js 6.67 kB 0 B
packages/core/dist/utils/json-utils.mjs 4.45 kB 0 B
packages/core/dist/utils/logger.js 2.58 kB 0 B
packages/core/dist/utils/logger.mjs 1.29 kB 0 B
packages/core/dist/utils/number-utils.js 3.32 kB 0 B
packages/core/dist/utils/number-utils.mjs 1.68 kB 0 B
packages/core/dist/utils/promise-queue.js 2.48 kB 0 B
packages/core/dist/utils/promise-queue.mjs 1.25 kB 0 B
packages/core/dist/utils/string-utils.js 3.73 kB 0 B
packages/core/dist/utils/string-utils.mjs 1.97 kB 0 B
packages/core/dist/utils/type-utils.js 7.43 kB 0 B
packages/core/dist/utils/type-utils.mjs 3.28 kB 0 B
packages/core/dist/utils/user-agent-utils.js 17.7 kB 0 B
packages/core/dist/utils/user-agent-utils.mjs 14.2 kB 0 B
packages/core/dist/vendor/uuidv7.js 8.3 kB 0 B
packages/core/dist/vendor/uuidv7.mjs 6.72 kB 0 B
packages/mcp/dist/extensions/analytics-parameters.js 6.53 kB 0 B
packages/mcp/dist/extensions/analytics-parameters.mjs 4.27 kB 0 B
packages/mcp/dist/extensions/capture.js 3.94 kB 0 B
packages/mcp/dist/extensions/capture.mjs 2.58 kB 0 B
packages/mcp/dist/extensions/client-********.js 6.23 kB 0 B
packages/mcp/dist/extensions/client-********.mjs 3.71 kB 0 B
packages/mcp/dist/extensions/compatibility.js 5.36 kB 0 B
packages/mcp/dist/extensions/compatibility.mjs 3.4 kB 0 B
packages/mcp/dist/extensions/constants.js 5.39 kB 0 B
packages/mcp/dist/extensions/constants.mjs 2.95 kB 0 B
packages/mcp/dist/extensions/context-parameters.js 2.75 kB 0 B
packages/mcp/dist/extensions/context-parameters.mjs 893 B 0 B
packages/mcp/dist/extensions/conversation-id.js 6.31 kB 0 B
packages/mcp/dist/extensions/conversation-id.mjs 3.58 kB 0 B
packages/mcp/dist/extensions/detect.js 3.77 kB 0 B
packages/mcp/dist/extensions/detect.mjs 1.49 kB 0 B
packages/mcp/dist/extensions/event-types.js 1.68 kB 0 B
packages/mcp/dist/extensions/event-types.mjs 459 B 0 B
packages/mcp/dist/extensions/exceptions.js 2.57 kB 0 B
packages/mcp/dist/extensions/exceptions.mjs 1.19 kB 0 B
packages/mcp/dist/extensions/headers.js 1.98 kB 0 B
packages/mcp/dist/extensions/headers.mjs 643 B 0 B
packages/mcp/dist/extensions/ids.js 2.01 kB 0 B
packages/mcp/dist/extensions/ids.mjs 637 B 0 B
packages/mcp/dist/extensions/instrument-********.js 4.92 kB 0 B
packages/mcp/dist/extensions/instrument-********.mjs 3.18 kB 0 B
packages/mcp/dist/extensions/instrument-highlevel.js 12.7 kB 0 B
packages/mcp/dist/extensions/instrument-highlevel.mjs 10.2 kB 0 B
packages/mcp/dist/extensions/instrumentation.js 27.8 kB 0 B
packages/mcp/dist/extensions/instrumentation.mjs 21.9 kB 0 B
packages/mcp/dist/extensions/intent.js 3.2 kB 0 B
packages/mcp/dist/extensions/intent.mjs 1.64 kB 0 B
packages/mcp/dist/extensions/internal.js 7.54 kB 0 B
packages/mcp/dist/extensions/internal.mjs 5.23 kB 0 B
packages/mcp/dist/extensions/lib-********.js 1.6 kB 0 B
packages/mcp/dist/extensions/lib-********.mjs 267 B 0 B
packages/mcp/dist/extensions/logger.js 1.72 kB 0 B
packages/mcp/dist/extensions/logger.mjs 380 B 0 B
packages/mcp/dist/extensions/mcp-********.js 4.68 kB 0 B
packages/mcp/dist/extensions/mcp-********.mjs 3.3 kB 0 B
packages/mcp/dist/extensions/mcp-sdk-compat.js 5.04 kB 0 B
packages/mcp/dist/extensions/mcp-sdk-compat.mjs 2.9 kB 0 B
packages/mcp/dist/extensions/model-parameters.js 3.49 kB 0 B
packages/mcp/dist/extensions/model-parameters.mjs 1.41 kB 0 B
packages/mcp/dist/extensions/output-instructions.js 6.11 kB 0 B
packages/mcp/dist/extensions/output-instructions.mjs 3.91 kB 0 B
packages/mcp/dist/extensions/posthog-events.js 11.7 kB 0 B
packages/mcp/dist/extensions/posthog-events.mjs 7.98 kB 0 B
packages/mcp/dist/extensions/posthog-mcp.js 6.94 kB 0 B
packages/mcp/dist/extensions/posthog-mcp.mjs 4.93 kB 0 B
packages/mcp/dist/extensions/request-headers.js 2.17 kB 0 B
packages/mcp/dist/extensions/request-headers.mjs 963 B 0 B
packages/mcp/dist/extensions/sanitization.js 4.49 kB 0 B
packages/mcp/dist/extensions/sanitization.mjs 2.86 kB 0 B
packages/mcp/dist/extensions/session-token.js 5.39 kB 0 B
packages/mcp/dist/extensions/session-token.mjs 3.62 kB 0 B
packages/mcp/dist/extensions/session.js 6.64 kB 0 B
packages/mcp/dist/extensions/session.mjs 4.12 kB 0 B
packages/mcp/dist/extensions/sink.js 4.37 kB 0 B
packages/mcp/dist/extensions/sink.mjs 2.67 kB 0 B
packages/mcp/dist/extensions/tools.js 3.51 kB 0 B
packages/mcp/dist/extensions/tools.mjs 1.63 kB 0 B
packages/mcp/dist/extensions/tracing-helpers.js 2.41 kB 0 B
packages/mcp/dist/extensions/tracing-helpers.mjs 772 B 0 B
packages/mcp/dist/extensions/transport-********.js 2.91 kB 0 B
packages/mcp/dist/extensions/transport-********.mjs 1.09 kB 0 B
packages/mcp/dist/extensions/truncation.js 11.5 kB 0 B
packages/mcp/dist/extensions/truncation.mjs 9.79 kB 0 B
packages/mcp/dist/index.js 8.78 kB 0 B
packages/mcp/dist/index.mjs 4.96 kB 0 B
packages/mcp/dist/types.js 603 B 0 B
packages/mcp/dist/types.mjs 0 B 0 B 🆕
packages/mcp/dist/version.js 1.21 kB 0 B
packages/mcp/dist/version.mjs 46 B 0 B
packages/next/dist/app/PostHogProvider.js 5.37 kB 0 B
packages/next/dist/client/ClientPostHogProvider.js 2.28 kB 0 B
packages/next/dist/client/hooks.js 172 B 0 B
packages/next/dist/client/PostHogPageView.js 4.23 kB 0 B
packages/next/dist/index.client.js 401 B 0 B
packages/next/dist/index.edge.js 570 B 0 B
packages/next/dist/index.js 554 B 0 B
packages/next/dist/index.react-server.js 420 B 0 B
packages/next/dist/middleware/postHogMiddleware.js 4.08 kB 0 B
packages/next/dist/pages.client.js 225 B 0 B
packages/next/dist/pages.edge.js 294 B 0 B
packages/next/dist/pages.js 347 B 0 B
packages/next/dist/pages/createPostHog.js 1.48 kB 0 B
packages/next/dist/pages/getServerSidePostHog.js 1.48 kB 0 B
packages/next/dist/pages/PostHogPageView.js 1.77 kB 0 B
packages/next/dist/pages/PostHogProvider.js 1.58 kB 0 B
packages/next/dist/server.edge.js 795 B 0 B
packages/next/dist/server/captureRequestError.js 5.26 kB 0 B
packages/next/dist/server/clientCache.edge.js 305 B 0 B
packages/next/dist/server/clientCache.js 1.54 kB 0 B
packages/next/dist/server/clientCache.node.js 305 B 0 B
packages/next/dist/server/createPostHog.js 1.44 kB 0 B
packages/next/dist/server/getPostHog.js 3.45 kB 0 B
packages/next/dist/server/onRequestError.js 1.39 kB 0 B
packages/next/dist/server/onRequestError.types.js 59 B 0 B
packages/next/dist/shared/browser.js 195 B 0 B
packages/next/dist/shared/config.js 2.23 kB 0 B
packages/next/dist/shared/constants.js 201 B 0 B
packages/next/dist/shared/cookie.js 540 B 0 B
packages/next/dist/shared/identity.js 2.56 kB 0 B
packages/next/dist/shared/tracing-headers.js 2.18 kB 0 B
packages/nextjs-config/dist/config.js 6.1 kB 0 B
packages/nextjs-config/dist/config.mjs 4.53 kB 0 B
packages/nextjs-config/dist/index.js 2.24 kB 0 B
packages/nextjs-config/dist/index.mjs 30 B 0 B
packages/nextjs-config/dist/strip-sourcemap-********.js 3.63 kB 0 B
packages/nextjs-config/dist/strip-sourcemap-********.mjs 1.77 kB 0 B
packages/nextjs-config/dist/utils.js 2.94 kB 0 B
packages/nextjs-config/dist/utils.mjs 826 B 0 B
packages/node/dist/ai-capture/batching.js 2.61 kB 0 B
packages/node/dist/ai-capture/batching.mjs 1.21 kB 0 B
packages/node/dist/ai-capture/routing.js 1.87 kB 0 B
packages/node/dist/ai-capture/routing.mjs 264 B 0 B
packages/node/dist/capture-v1/config.js 1.5 kB 0 B
packages/node/dist/capture-v1/config.mjs 292 B 0 B
packages/node/dist/capture-v1/errors.js 1.89 kB 0 B
packages/node/dist/capture-v1/errors.mjs 694 B 0 B
packages/node/dist/capture-v1/routing.js 1.68 kB 0 B
packages/node/dist/capture-v1/routing.mjs 279 B 0 B
packages/node/dist/capture-v1/sender.js 11.4 kB 0 B
packages/node/dist/capture-v1/sender.mjs 9.94 kB 0 B
packages/node/dist/capture-v1/transform.js 5.13 kB 0 B
packages/node/dist/capture-v1/transform.mjs 3.65 kB 0 B
packages/node/dist/capture-v1/types.js 603 B 0 B
packages/node/dist/capture-v1/types.mjs 0 B 0 B 🆕
packages/node/dist/client.js 59.5 kB 0 B
packages/node/dist/client.mjs 56.2 kB 0 B
packages/node/dist/entrypoints/index.edge.js 3.85 kB 0 B
packages/node/dist/entrypoints/index.edge.mjs 720 B 0 B
packages/node/dist/entrypoints/index.node.js 6.05 kB 0 B
packages/node/dist/entrypoints/index.node.mjs 1.43 kB 0 B
packages/node/dist/entrypoints/nestjs.js 2.31 kB 0 B
packages/node/dist/entrypoints/nestjs.mjs 42 B 0 B
packages/node/dist/experimental.js 870 B 0 B
packages/node/dist/experimental.mjs 267 B 0 B
packages/node/dist/exports.js 6.75 kB 0 B
packages/node/dist/exports.mjs 582 B 0 B
packages/node/dist/extensions/context/context.js 2.13 kB 0 B
packages/node/dist/extensions/context/context.mjs 863 B 0 B
packages/node/dist/extensions/context/types.js 603 B 0 B
packages/node/dist/extensions/context/types.mjs 0 B 0 B 🆕
packages/node/dist/extensions/error-tracking/autocapture.js 5.19 kB 0 B
packages/node/dist/extensions/error-tracking/autocapture.mjs 3.62 kB 0 B
packages/node/dist/extensions/error-tracking/index.js 4.38 kB 0 B
packages/node/dist/extensions/error-tracking/index.mjs 3.17 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.js 11.6 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/context-lines.node.mjs 9.64 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/module.node.js 2.78 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/module.node.mjs 1.45 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/relative-path.node.js 1.97 kB 0 B
packages/node/dist/extensions/error-tracking/modifiers/relative-path.node.mjs 624 B 0 B
packages/node/dist/extensions/express.js 4.97 kB 0 B
packages/node/dist/extensions/express.mjs 2.78 kB 0 B
packages/node/dist/extensions/feature-flags/cache.js 603 B 0 B
packages/node/dist/extensions/feature-flags/cache.mjs 0 B 0 B 🆕
packages/node/dist/extensions/feature-flags/crypto.js 1.27 kB 0 B
packages/node/dist/extensions/feature-flags/crypto.mjs 63 B 0 B
packages/node/dist/extensions/feature-flags/feature-flags.js 32.2 kB 0 B
packages/node/dist/extensions/feature-flags/feature-flags.mjs 29.8 kB 0 B
packages/node/dist/extensions/nestjs.js 5.62 kB 0 B
packages/node/dist/extensions/nestjs.mjs 3.42 kB 0 B
packages/node/dist/extensions/sentry-integration.js 4.88 kB 0 B
packages/node/dist/extensions/sentry-integration.mjs 3.36 kB 0 B
packages/node/dist/extensions/tracing-headers.js 3.31 kB 0 B
packages/node/dist/extensions/tracing-headers.mjs 1.53 kB 0 B
packages/node/dist/extensions/url-utils.js 2.22 kB 0 B
packages/node/dist/extensions/url-utils.mjs 785 B 0 B
packages/node/dist/feature-flag-evaluations.js 6.12 kB 0 B
packages/node/dist/feature-flag-evaluations.mjs 4.77 kB 0 B
packages/node/dist/gzip.node.js 1.74 kB 0 B
packages/node/dist/gzip.node.mjs 416 B 0 B
packages/node/dist/storage-memory.js 1.52 kB 0 B
packages/node/dist/storage-memory.mjs 297 B 0 B
packages/node/dist/types.js 1.43 kB 0 B
packages/node/dist/types.mjs 224 B 0 B
packages/node/dist/version.js 1.21 kB 0 B
packages/node/dist/version.mjs 46 B 0 B
packages/nuxt/dist/module.mjs 5.92 kB 0 B
packages/nuxt/dist/runtime/composables/useFeatureFlagEnabled.js 566 B 0 B
packages/nuxt/dist/runtime/composables/useFeatureFlagPayload.js 690 B 0 B
packages/nuxt/dist/runtime/composables/useFeatureFlagVariantKey.js 591 B 0 B
packages/nuxt/dist/runtime/composables/usePostHog.js 128 B 0 B
packages/nuxt/dist/runtime/nitro-plugin-v2.js 480 B 0 B
packages/nuxt/dist/runtime/nitro-plugin-v3.js 574 B 0 B
packages/nuxt/dist/runtime/nitro-plugin.js 1.03 kB 0 B
packages/nuxt/dist/runtime/vue-plugin.js 1.13 kB 0 B
packages/openfeature-node-provider/dist/index.js 1.76 kB 0 B
packages/openfeature-node-provider/dist/index.mjs 190 B 0 B
packages/openfeature-node-provider/dist/mapping.js 5.32 kB 0 B
packages/openfeature-node-provider/dist/mapping.mjs 3.21 kB 0 B
packages/openfeature-node-provider/dist/provider.js 3.99 kB 0 B
packages/openfeature-node-provider/dist/provider.mjs 2.6 kB 0 B
packages/openfeature-web-provider/dist/index.js 1.75 kB 0 B
packages/openfeature-web-provider/dist/index.mjs 184 B 0 B
packages/openfeature-web-provider/dist/mapping.js 5.29 kB 0 B
packages/openfeature-web-provider/dist/mapping.mjs 3.18 kB 0 B
packages/openfeature-web-provider/dist/provider.js 4.41 kB 0 B
packages/openfeature-web-provider/dist/provider.mjs 3.06 kB 0 B
packages/plugin-utils/dist/chunk-ids.js 3.86 kB 0 B
packages/plugin-utils/dist/chunk-ids.mjs 2.05 kB 0 B
packages/plugin-utils/dist/cli.js 4.37 kB 0 B
packages/plugin-utils/dist/cli.mjs 2.72 kB 0 B
packages/plugin-utils/dist/config.js 3.5 kB 0 B
packages/plugin-utils/dist/config.mjs 2.26 kB 0 B
packages/plugin-utils/dist/index.js 4.98 kB 0 B
packages/plugin-utils/dist/index.mjs 250 B 0 B
packages/plugin-utils/dist/spawn-local.js 3.08 kB 0 B
packages/plugin-utils/dist/spawn-local.mjs 1.66 kB 0 B
packages/plugin-utils/dist/utils.js 3.27 kB 0 B
packages/plugin-utils/dist/utils.mjs 1.3 kB 0 B
packages/react-native/dist/autocapture.js 8.31 kB 0 B
packages/react-native/dist/error-tracking/index.js 9.97 kB 0 B
packages/react-native/dist/error-tracking/utils.js 2.58 kB 0 B
packages/react-native/dist/frameworks/wix-navigation.js 1.3 kB 0 B
packages/react-native/dist/hooks/useFeatureFlag.js 1.86 kB 0 B
packages/react-native/dist/hooks/useFeatureFlagResult.js 983 B 0 B
packages/react-native/dist/hooks/useFeatureFlags.js 941 B 0 B
packages/react-native/dist/hooks/useNavigationTracker.js 2.45 kB 0 B
packages/react-native/dist/hooks/usePostHog.js 544 B 0 B
packages/react-native/dist/hooks/utils.js 988 B 0 B
packages/react-native/dist/index.js 4.33 kB 0 B
packages/react-native/dist/logs-********.js 3.66 kB 0 B
packages/react-native/dist/native-deps.js 8.73 kB 0 B
packages/react-native/dist/optional/OptionalAsyncStorage.js 299 B 0 B
packages/react-native/dist/optional/OptionalExpoApplication.js 377 B 0 B
packages/react-native/dist/optional/OptionalExpoDevice.js 347 B 0 B
packages/react-native/dist/optional/OptionalExpoFileSystem.js 386 B 0 B
packages/react-native/dist/optional/OptionalExpoFileSystemLegacy.js 423 B 0 B
packages/react-native/dist/optional/OptionalExpoLocalization.js 383 B 0 B
packages/react-native/dist/optional/OptionalPlugin.js 891 B 0 B
packages/react-native/dist/optional/OptionalReactNativeDeviceInfo.js 415 B 0 B
packages/react-native/dist/optional/OptionalReactNativeLocalize.js 303 B 0 B
packages/react-native/dist/optional/OptionalReactNativeNavigation.js 415 B 0 B
packages/react-native/dist/optional/OptionalReactNativeNavigationWix.js 443 B 0 B
packages/react-native/dist/optional/OptionalReactNativeSafeArea.js 644 B 0 B
packages/react-native/dist/optional/OptionalReactNativeSvg.js 872 B 0 B
packages/react-native/dist/posthog-rn.js 67.4 kB 0 B
packages/react-native/dist/PostHogContext.js 329 B 0 B
packages/react-native/dist/PostHogErrorBoundary.js 3.19 kB 0 B
packages/react-native/dist/PostHogMaskView.js 1.68 kB 0 B
packages/react-native/dist/PostHogProvider.js 6 kB 0 B
packages/react-native/dist/storage.js 5.76 kB 0 B
packages/react-native/dist/surveys/components/BottomSection.js 1.51 kB 0 B
packages/react-native/dist/surveys/components/Cancel.js 1.1 kB 0 B
packages/react-native/dist/surveys/components/ConfirmationMessage.js 1.76 kB 0 B
packages/react-native/dist/surveys/components/IntroMessage.js 1.65 kB 0 B
packages/react-native/dist/surveys/components/QuestionHeader.js 1.47 kB 0 B
packages/react-native/dist/surveys/components/QuestionTypes.js 14 kB 0 B
packages/react-native/dist/surveys/components/SurveyModal.js 7.24 kB 0 B
packages/react-native/dist/surveys/components/Surveys.js 6.58 kB 0 B
packages/react-native/dist/surveys/getActiveMatchingSurveys.js 2.69 kB 0 B
packages/react-native/dist/surveys/icons.js 10 kB 0 B
packages/react-native/dist/surveys/index.js 600 B 0 B
packages/react-native/dist/surveys/PostHogSurveyProvider.js 6.73 kB 0 B
packages/react-native/dist/surveys/safeStyleSheet.js 448 B 0 B
packages/react-native/dist/surveys/survey-translations.js 1.11 kB 0 B
packages/react-native/dist/surveys/surveys-utils.js 11.5 kB 0 B
packages/react-native/dist/surveys/useActivatedSurveys.js 3.68 kB 0 B
packages/react-native/dist/surveys/useSurveyStorage.js 2.48 kB 0 B
packages/react-native/dist/tooling/expoconfig.js 23.6 kB 0 B
packages/react-native/dist/tooling/metroconfig.js 2.32 kB 0 B
packages/react-native/dist/tooling/posthogMetroSerializer.js 7.74 kB 0 B
packages/react-native/dist/tooling/utils.js 4.2 kB 0 B
packages/react-native/dist/tooling/vendor/expo/expoconfig.js 70 B 0 B
packages/react-native/dist/tooling/vendor/metro/countLines.js 237 B 0 B
packages/react-native/dist/tooling/vendor/metro/utils.js 3.51 kB 0 B
packages/react-native/dist/types.js 70 B 0 B
packages/react-native/dist/utils.js 1.3 kB 0 B
packages/react-native/dist/version.js 130 B 0 B
packages/react/dist/esm/index.js 22.5 kB 0 B
packages/react/dist/esm/slim/index.js 18.9 kB 0 B
packages/react/dist/esm/surveys/index.js 4.75 kB 0 B
packages/react/dist/umd/index.js 25.9 kB 0 B
packages/react/dist/umd/slim/index.js 21.8 kB 0 B
packages/react/dist/umd/surveys/index.js 5.52 kB 0 B
packages/rollup-plugin/dist/index.js 7.6 kB 0 B
packages/rrweb/packer/dist/base-********.cjs 18.3 kB 0 B
packages/rrweb/packer/dist/base-********.js 18.2 kB 0 B
packages/rrweb/packer/dist/base-********.umd.cjs 18.7 kB 0 B
packages/rrweb/packer/dist/base-********.umd.min.cjs 9.5 kB 0 B
packages/rrweb/packer/dist/pack.cjs 347 B 0 B
packages/rrweb/packer/dist/pack.js 285 B 0 B
packages/rrweb/packer/dist/pack.umd.cjs 1.63 kB 0 B
packages/rrweb/packer/dist/pack.umd.min.cjs 1.11 kB 0 B
packages/rrweb/packer/dist/packer.cjs 257 B 0 B
packages/rrweb/packer/dist/packer.js 136 B 0 B
packages/rrweb/packer/dist/packer.umd.cjs 662 B 0 B
packages/rrweb/packer/dist/packer.umd.min.cjs 626 B 0 B
packages/rrweb/packer/dist/unpack.cjs 769 B 0 B
packages/rrweb/packer/dist/unpack.js 702 B 0 B
packages/rrweb/packer/dist/unpack.umd.cjs 1.17 kB 0 B
packages/rrweb/packer/dist/unpack.umd.min.cjs 955 B 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.cjs 37.6 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.js 37.5 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.umd.cjs 38 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-record/dist/rrweb-plugin-canvas-webrtc-record.umd.min.cjs 22.2 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.cjs 34.3 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.js 34.2 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.umd.cjs 34.7 kB 0 B
packages/rrweb/plugins/rrweb-plugin-canvas-webrtc-replay/dist/rrweb-plugin-canvas-webrtc-replay.umd.min.cjs 20.5 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.cjs 15.8 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.js 15.7 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.umd.cjs 16.3 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-record/dist/rrweb-plugin-console-record.umd.min.cjs 7.66 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.cjs 5.01 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.js 4.9 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.umd.cjs 5.44 kB 0 B
packages/rrweb/plugins/rrweb-plugin-console-replay/dist/rrweb-plugin-console-replay.umd.min.cjs 2.64 kB 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.cjs 681 B 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.js 548 B 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.umd.cjs 1.12 kB 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-record/dist/rrweb-plugin-sequential-id-record.umd.min.cjs 829 B 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.cjs 933 B 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.js 820 B 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.umd.cjs 1.37 kB 0 B
packages/rrweb/plugins/rrweb-plugin-sequential-id-replay/dist/rrweb-plugin-sequential-id-replay.umd.min.cjs 968 B 0 B
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.cjs 160 kB 0 B
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.js 160 kB 0 B
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.umd.cjs 162 kB 0 B
packages/rrweb/rrdom-nodejs/dist/rrdom-nodejs.umd.min.cjs 74.9 kB 0 B
packages/rrweb/rrdom/dist/rrdom.cjs 186 kB 0 B
packages/rrweb/rrdom/dist/rrdom.js 185 kB 0 B
packages/rrweb/rrdom/dist/rrdom.umd.cjs 187 kB 0 B
packages/rrweb/rrdom/dist/rrdom.umd.min.cjs 85.5 kB 0 B
packages/rrweb/types/dist/rrweb-types.cjs 5.75 kB 0 B
packages/rrweb/types/dist/rrweb-types.js 5.46 kB 0 B
packages/rrweb/types/dist/rrweb-types.umd.cjs 6.16 kB 0 B
packages/rrweb/types/dist/rrweb-types.umd.min.cjs 2.86 kB 0 B
packages/rrweb/utils/dist/rrweb-utils.cjs 7.76 kB 0 B
packages/rrweb/utils/dist/rrweb-utils.js 7.3 kB 0 B
packages/rrweb/utils/dist/rrweb-utils.umd.cjs 8.24 kB 0 B
packages/rrweb/utils/dist/rrweb-utils.umd.min.cjs 4.09 kB 0 B
packages/types/dist/capture-log.js 603 B 0 B
packages/types/dist/capture-log.mjs 0 B 0 B 🆕
packages/types/dist/capture-metric.js 1.37 kB 0 B
packages/types/dist/capture-metric.mjs 93 B 0 B
packages/types/dist/capture.js 603 B 0 B
packages/types/dist/capture.mjs 0 B 0 B 🆕
packages/types/dist/common.js 603 B 0 B
packages/types/dist/common.mjs 0 B 0 B 🆕
packages/types/dist/feature-flags.js 603 B 0 B
packages/types/dist/feature-flags.mjs 0 B 0 B 🆕
packages/types/dist/index.js 1.45 kB 0 B
packages/types/dist/index.mjs 122 B 0 B
packages/types/dist/posthog-config.js 603 B 0 B
packages/types/dist/posthog-config.mjs 0 B 0 B 🆕
packages/types/dist/posthog.js 603 B 0 B
packages/types/dist/posthog.mjs 0 B 0 B 🆕
packages/types/dist/request.js 603 B 0 B
packages/types/dist/request.mjs 0 B 0 B 🆕
packages/types/dist/segment.js 603 B 0 B
packages/types/dist/segment.mjs 0 B 0 B 🆕
packages/types/dist/session-recording.js 603 B 0 B
packages/types/dist/session-recording.mjs 0 B 0 B 🆕
packages/types/dist/survey.js 603 B 0 B
packages/types/dist/survey.mjs 0 B 0 B 🆕
packages/types/dist/toolbar.js 603 B 0 B
packages/types/dist/toolbar.mjs 0 B 0 B 🆕
packages/types/dist/tree-shakeable.js 603 B 0 B
packages/types/dist/tree-shakeable.mjs 0 B 0 B 🆕
packages/web/dist/index.cjs 14 kB 0 B
packages/web/dist/index.mjs 14 kB 0 B
packages/webpack-plugin/dist/config.js 1.47 kB 0 B
packages/webpack-plugin/dist/config.mjs 480 B 0 B
packages/webpack-plugin/dist/index.js 7.39 kB 0 B
packages/webpack-plugin/dist/index.mjs 3.58 kB 0 B
tooling/changelog/dist/index.js 3.31 kB 0 B
tooling/rollup-utils/dist/index.js 1.17 kB 0 B

compressed-size-action

@posthog

posthog Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor Author

PostHog Review alpha 🦔 If you find any issues helpful - please reply "valid", "invalid", etc., for evaluation purposes 🙏

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

PostHog Review

Found 1 must fix, 1 should fix, 1 consider.

Comment on lines +26 to +32
/**
* Sentinel that replaces the text content of every `<script>` node during
* serialization (see snapshot.ts). It keeps real script source out of the
* snapshot and marks the node as a script for rebuild. `rebuild.ts` reads this
* value back and must not render it, so the two sides share this one constant.
*/
export const SCRIPT_PLACEHOLDER = 'SCRIPT_PLACEHOLDER';

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Redact script character-data mutations

should_fix security

Why we think it's a valid issue
  • Checked: the record-side character-data path (packages/rrweb/rrweb/src/record/mutation.ts), the payload filter that decides which text mutations ship, the replay-side apply loop (packages/rrweb/rrweb/src/replay/index.ts), isIgnored in packages/rrweb/rrweb/src/utils.ts, the slimDOM gate in packages/rrweb/rrweb-snapshot/src/snapshot.ts, and the posthog-js recorder defaults in packages/browser/src/extensions/replay/external/lazy-loaded-session-recorder.ts.
  • Found: packages/rrweb/rrweb/src/record/mutation.ts:666 reads dom.textContent(m.target) and pushes it at line 673. The only transform is needMaskingText. There is no parent-tag check, so no SCRIPT_PLACEHOLDER substitution. serializeTextNode (packages/rrweb/rrweb-snapshot/src/snapshot.ts:681) is the only place that applies the sentinel, and the character-data path never calls it.
  • Found: the mutation survives the payload filters at packages/rrweb/rrweb/src/record/mutation.ts:549-551. Those filters drop ids not present in the mirror. A script text node holds a real id, because serializeTextNode gives it the non-whitespace value SCRIPT_PLACEHOLDER, so the whitespace-only ignore rule at packages/rrweb/rrweb-snapshot/src/snapshot.ts:1329-1333 does not apply. Recorded event fixtures confirm the id, for example packages/rrweb/rrweb/test/events/webgl.ts:84.
  • Found: isIgnored (packages/rrweb/rrweb/src/utils.ts:300-314) only rejects IGNORED_NODE and slim-DOM title mutations. It does not reject script text nodes.
  • Found: replay assigns the value with no sentinel check at packages/rrweb/rrweb/src/replay/index.ts:2018 (target.textContent = mutation.value;). The target is the text child of the <noscript> that tagMap produced at packages/rrweb/rrweb-snapshot/src/rebuild.ts:21. The new empty-text-node guard at packages/rrweb/rrweb-snapshot/src/rebuild.ts:133 runs only on the build path, so it cannot undo this later write.
  • Found: the path is on by default. posthog-js sets slimDOMOptions: {} at packages/browser/src/extensions/replay/external/lazy-loaded-session-recorder.ts:2598, so slimDOMOptions.script is falsy and <script> elements are recorded, not excluded.
  • Impact: confirmed. A direct write to the script's Text node — script.firstChild.data = ..., .nodeValue = ..., appendData, or replaceData — stores the raw script text in the recording and renders it inside the rebuilt <noscript> on replay. In a shadow root the document-scoped noscript { display: none } rule does not reach it, so the text becomes visible. This is the same leak class the PR closes for the sentinel.
  • Impact: the reachable set is narrower than the finding implies. textContent =, .text =, innerHTML =, and appendChild all produce childList mutations, which re-serialize through serializeTextNode and stay redacted. Only in-place Text-node writes reach the gap, and the common instance of that pattern is a JSON or JSON-LD data script, whose content is public.
  • Priority: lowered to should_fix. The gap is real and verified, but it predates this PR, sits in two files the PR does not touch, and the PR neither creates nor widens it — before the change the same write overwrote the sentinel text node in exactly the same way. It should not block a narrow, correct fix.
Issue description

The new contract says every script body uses the sentinel. Character-data mutations do not call serializeTextNode. The recorder stores their raw value, and replay assigns it directly. A changed script text node can therefore store and render its source inside the rebuilt <noscript>. This bypasses the privacy boundary for incremental updates.

Suggested fix

Store the sentinel when a character-data mutation belongs to a script. Also ignore script text mutations during replay for older recordings. Add a test that changes script.firstChild.data after a full snapshot.

Prompt to fix with AI (copy-paste)
## Context
@packages/rrweb/rrweb-snapshot/src/utils.ts#L26-32

<issue_description>
The new contract says every script body uses the sentinel. Character-data mutations do not call `serializeTextNode`. The recorder stores their raw value, and replay assigns it directly. A changed script text node can therefore store and render its source inside the rebuilt `<noscript>`. This bypasses the privacy boundary for incremental updates.
</issue_description>

<issue_validation>
- **Checked:** the record-side character-data path (`packages/rrweb/rrweb/src/record/mutation.ts`), the payload filter that decides which text mutations ship, the replay-side apply loop (`packages/rrweb/rrweb/src/replay/index.ts`), `isIgnored` in `packages/rrweb/rrweb/src/utils.ts`, the slimDOM gate in `packages/rrweb/rrweb-snapshot/src/snapshot.ts`, and the posthog-js recorder defaults in `packages/browser/src/extensions/replay/external/lazy-loaded-session-recorder.ts`.
- **Found:** `packages/rrweb/rrweb/src/record/mutation.ts:666` reads `dom.textContent(m.target)` and pushes it at line 673. The only transform is `needMaskingText`. There is no parent-tag check, so no `SCRIPT_PLACEHOLDER` substitution. `serializeTextNode` (`packages/rrweb/rrweb-snapshot/src/snapshot.ts:681`) is the only place that applies the sentinel, and the character-data path never calls it.
- **Found:** the mutation survives the payload filters at `packages/rrweb/rrweb/src/record/mutation.ts:549-551`. Those filters drop ids not present in the mirror. A script text node holds a real id, because `serializeTextNode` gives it the non-whitespace value `SCRIPT_PLACEHOLDER`, so the whitespace-only ignore rule at `packages/rrweb/rrweb-snapshot/src/snapshot.ts:1329-1333` does not apply. Recorded event fixtures confirm the id, for example `packages/rrweb/rrweb/test/events/webgl.ts:84`.
- **Found:** `isIgnored` (`packages/rrweb/rrweb/src/utils.ts:300-314`) only rejects `IGNORED_NODE` and slim-DOM title mutations. It does not reject script text nodes.
- **Found:** replay assigns the value with no sentinel check at `packages/rrweb/rrweb/src/replay/index.ts:2018` (`target.textContent = mutation.value;`). The target is the text child of the `<noscript>` that `tagMap` produced at `packages/rrweb/rrweb-snapshot/src/rebuild.ts:21`. The new empty-text-node guard at `packages/rrweb/rrweb-snapshot/src/rebuild.ts:133` runs only on the build path, so it cannot undo this later write.
- **Found:** the path is on by default. posthog-js sets `slimDOMOptions: {}` at `packages/browser/src/extensions/replay/external/lazy-loaded-session-recorder.ts:2598`, so `slimDOMOptions.script` is falsy and `<script>` elements are recorded, not excluded.
- **Impact:** confirmed. A direct write to the script's Text node — `script.firstChild.data = ...`, `.nodeValue = ...`, `appendData`, or `replaceData` — stores the raw script text in the recording and renders it inside the rebuilt `<noscript>` on replay. In a shadow root the document-scoped `noscript { display: none }` rule does not reach it, so the text becomes visible. This is the same leak class the PR closes for the sentinel.
- **Impact:** the reachable set is narrower than the finding implies. `textContent =`, `.text =`, `innerHTML =`, and `appendChild` all produce childList mutations, which re-serialize through `serializeTextNode` and stay redacted. Only in-place Text-node writes reach the gap, and the common instance of that pattern is a JSON or JSON-LD data script, whose content is public.
- **Priority:** lowered to `should_fix`. The gap is real and verified, but it predates this PR, sits in two files the PR does not touch, and the PR neither creates nor widens it — before the change the same write overwrote the sentinel text node in exactly the same way. It should not block a narrow, correct fix.
</issue_validation>

## Task
Investigate the issue and solve it

<potential_solution>
Store the sentinel when a character-data mutation belongs to a script. Also ignore script text mutations during replay for older recordings. Add a test that changes `script.firstChild.data` after a full snapshot.
</potential_solution>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirmed this is a real, pre-existing gap, but it is out of scope for this PR, so I'm escalating rather than fixing it here.

What I verified at the current head:

  • Record side (record/mutation.ts, the characterData branch): a text mutation on a <script>'s text child is captured with only text-masking applied — there is no parent-tag check and no SCRIPT_PLACEHOLDER substitution. The sentinel is only ever applied in serializeTextNode (snapshot.ts), which the character-data path never calls.
  • Replay side (replay/index.ts): the text mutation's value is written straight onto the target with no sentinel/redaction guard.
  • This PR's new empty-text-node guard (rebuild.ts) only runs on the build path, so it can't intercept a later character-data write.

So an in-place write to a script's text node (.data =, .nodeValue =, appendData, replaceData) can store raw script source and render it inside the rebuilt <noscript> — visible in a shadow root, the same leak class this PR closes for the sentinel.

Why I'm not fixing it in this PR: it lives entirely in record/mutation.ts and replay/index.ts, two files this PR doesn't touch, and (as the finding itself notes) this PR neither creates nor widens it — before the change the same write overwrote the sentinel text node in exactly the same way. It's a separate, pre-existing privacy-redaction boundary, and a correct fix is a design decision (redact script-parented character-data mutations on the record side by substituting the sentinel keyed on the target's parent tag, with new recording tests, and/or add a replay-side guard).

What a human needs to decide: whether to take this on as its own follow-up PR against the record/replay paths, and whether the reachable set (in practice, in-place writes to public JSON/JSON-LD data scripts) justifies the record-side change now. It should not block this narrow rebuild-path fix from merging.

}
if (isScript) {
text = 'SCRIPT_PLACEHOLDER';
text = SCRIPT_PLACEHOLDER;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Redact lowercase script elements

consider security

Why we think it's a valid issue
  • Checked: serializeTextNode and its isScript guard, getValidTagName, isSVGElement, slimDOMExcluded, the rebuild path for SVG-namespaced nodes in packages/rrweb/rrweb-snapshot/src/rebuild.ts, the posthog-js recorder defaults in packages/browser/src/extensions/replay/external/lazy-loaded-session-recorder.ts, and git diff main..HEAD to see what the PR actually changed here.
  • Found: the premise holds, and the repo itself relies on it. isSVGElement at packages/rrweb/rrweb-snapshot/src/snapshot.ts:167-169 tests el.tagName === 'svg' in lowercase. That check only works because SVG-namespace elements report a lowercase tagName. The same rule makes an SVG <script> report script, so packages/rrweb/rrweb-snapshot/src/snapshot.ts:646 (parentTagName === 'SCRIPT') does not match it and the sentinel assignment at line 682 never runs.
  • Found: the codebase is inconsistent on this. getValidTagName normalizes with toLowerCase at packages/rrweb/rrweb-snapshot/src/snapshot.ts:63, and slimDOMExcluded compares the normalized name against lowercase 'script' at packages/rrweb/rrweb-snapshot/src/snapshot.ts:1100. Only the redaction check compares the raw DOM tagName against an uppercase literal.
  • Found: nothing else stops the text node. serializeNodeWithId recurses into SVG children, and the slimDOM script exclusion is off by default — posthog-js sets slimDOMOptions: {} at packages/browser/src/extensions/replay/external/lazy-loaded-session-recorder.ts:2598. So the raw source of an inline <svg><script> is stored verbatim in the snapshot.
  • Found: the render half of the claim does not hold for SVG. The element serializes with isSVG: true (packages/rrweb/rrweb-snapshot/src/snapshot.ts:1072), so rebuild takes the createElementNS branch at packages/rrweb/rrweb-snapshot/src/rebuild.ts:174 and produces an SVG-namespace noscript. That is an unrecognized SVG element, so neither it nor its children render. The visible-text leak is limited to the XHTML case, which the finding scopes correctly.
  • Found: the gap predates this PR. The diff on this file is only text = 'SCRIPT_PLACEHOLDER'text = SCRIPT_PLACEHOLDER, plus the import. The isScript comparison is untouched.
  • Impact: confirmed but narrow. An inline <svg><script> writes its real source into the recording instead of the sentinel, which breaks the redaction the PR just documented. The PR's new comment at packages/rrweb/rrweb-snapshot/src/utils.ts:26-32 asserts the sentinel replaces the text of "every <script> node", and that wording is now demonstrably wrong. The fix is one normalization, and it causes no regression: an SVG script would then rebuild as an empty text node, exactly like an HTML one.
  • Priority: lowered to consider. Inline SVG scripts are uncommon on real pages, the leaked content is page code rather than user data, and the SVG case produces no visible render. The XHTML variant is the only path that renders, and XHTML-served documents are effectively extinct, so this does not justify blocking a narrow fix.
Issue description

This assignment runs only when parent.tagName equals uppercase SCRIPT. SVG and XHTML elements expose lowercase script. Their snapshots therefore store the real script source. XHTML script text can also render inside a replayed shadow root.

Suggested fix

Normalize the parent name before the check, such as parentTagName?.toLowerCase() === 'script'. Add browser tests for SVG and XHTML scripts. Assert that snapshot bytes exclude the source and replay shows no script text.

Prompt to fix with AI (copy-paste)
## Context
@packages/rrweb/rrweb-snapshot/src/snapshot.ts#L682

<issue_description>
This assignment runs only when `parent.tagName` equals uppercase `SCRIPT`. SVG and XHTML elements expose lowercase `script`. Their snapshots therefore store the real script source. XHTML script text can also render inside a replayed shadow root.
</issue_description>

<issue_validation>
- **Checked:** `serializeTextNode` and its `isScript` guard, `getValidTagName`, `isSVGElement`, `slimDOMExcluded`, the rebuild path for SVG-namespaced nodes in `packages/rrweb/rrweb-snapshot/src/rebuild.ts`, the posthog-js recorder defaults in `packages/browser/src/extensions/replay/external/lazy-loaded-session-recorder.ts`, and `git diff main..HEAD` to see what the PR actually changed here.
- **Found:** the premise holds, and the repo itself relies on it. `isSVGElement` at `packages/rrweb/rrweb-snapshot/src/snapshot.ts:167-169` tests `el.tagName === 'svg'` in lowercase. That check only works because SVG-namespace elements report a lowercase `tagName`. The same rule makes an SVG `<script>` report `script`, so `packages/rrweb/rrweb-snapshot/src/snapshot.ts:646` (`parentTagName === 'SCRIPT'`) does not match it and the sentinel assignment at line 682 never runs.
- **Found:** the codebase is inconsistent on this. `getValidTagName` normalizes with `toLowerCase` at `packages/rrweb/rrweb-snapshot/src/snapshot.ts:63`, and `slimDOMExcluded` compares the normalized name against lowercase `'script'` at `packages/rrweb/rrweb-snapshot/src/snapshot.ts:1100`. Only the redaction check compares the raw DOM `tagName` against an uppercase literal.
- **Found:** nothing else stops the text node. `serializeNodeWithId` recurses into SVG children, and the slimDOM script exclusion is off by default — posthog-js sets `slimDOMOptions: {}` at `packages/browser/src/extensions/replay/external/lazy-loaded-session-recorder.ts:2598`. So the raw source of an inline `<svg><script>` is stored verbatim in the snapshot.
- **Found:** the render half of the claim does not hold for SVG. The element serializes with `isSVG: true` (`packages/rrweb/rrweb-snapshot/src/snapshot.ts:1072`), so rebuild takes the `createElementNS` branch at `packages/rrweb/rrweb-snapshot/src/rebuild.ts:174` and produces an SVG-namespace `noscript`. That is an unrecognized SVG element, so neither it nor its children render. The visible-text leak is limited to the XHTML case, which the finding scopes correctly.
- **Found:** the gap predates this PR. The diff on this file is only `text = 'SCRIPT_PLACEHOLDER'` → `text = SCRIPT_PLACEHOLDER`, plus the import. The `isScript` comparison is untouched.
- **Impact:** confirmed but narrow. An inline `<svg><script>` writes its real source into the recording instead of the sentinel, which breaks the redaction the PR just documented. The PR's new comment at `packages/rrweb/rrweb-snapshot/src/utils.ts:26-32` asserts the sentinel replaces the text of "every `<script>` node", and that wording is now demonstrably wrong. The fix is one normalization, and it causes no regression: an SVG script would then rebuild as an empty text node, exactly like an HTML one.
- **Priority:** lowered to `consider`. Inline SVG scripts are uncommon on real pages, the leaked content is page code rather than user data, and the SVG case produces no visible render. The XHTML variant is the only path that renders, and XHTML-served documents are effectively extinct, so this does not justify blocking a narrow fix.
</issue_validation>

## Task
Investigate the issue and solve it

<potential_solution>
Normalize the parent name before the check, such as `parentTagName?.toLowerCase() === 'script'`. Add browser tests for SVG and XHTML scripts. Assert that snapshot bytes exclude the source and replay shows no script text.
</potential_solution>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirmed this is a real redaction gap at the current head, but I'm escalating rather than changing it unattended because it's a privacy/redaction boundary and its verification needs the browser suite.

What I verified: in serializeTextNode, the script check compares the raw DOM tagName against the uppercase literal 'SCRIPT'. HTML elements report an uppercased tag name, but SVG-namespace and XHTML <script> elements report lowercase script, so the check misses them and their real source is written into the snapshot instead of the SCRIPT_PLACEHOLDER sentinel. That also makes this PR's new comment ("the sentinel replaces the text of every <script> node") inaccurate for that edge case. The rest of the file already lowercases tag names (e.g. getValidTagName, the slimDOM script exclusion), so only this check is inconsistent.

The suggested one-token normalization (comparing parentTagName?.toLowerCase() === 'script') is contained and, per the finding, causes no regression — an SVG script would then rebuild as an empty text node like an HTML one.

Why a human should take it: (1) this is redaction logic whose job is keeping potentially-sensitive script bodies out of recordings, so a maintainer should sign off on the change rather than have it applied autonomously; (2) the finding's own acceptance test — assert the snapshot bytes exclude the source and replay shows no script text, for both SVG and XHTML — needs the real-Chrome integration suite, which cannot run in this sandbox (only the jsdom serialization half is provable here). While deciding, please also consider whether the sibling isStyle check (same uppercase-only comparison, so SVG <style> is affected too) should get the same normalization.

Impact is narrow, so this shouldn't block the PR: inline SVG scripts are uncommon, the SVG case rebuilds as a non-rendering SVG-namespace element (so no visible leak, only a stored-bytes leak), and XHTML-served documents — the only path that would render — are effectively extinct.

Comment thread .changeset/noscript-placeholder-shadow-root.md Outdated
The changeset bumped @posthog/rrweb-snapshot, an internal package that is
deliberately excluded from the release publish matrix. posthog-js links the
rrweb packages only via devDependencies, so the changesets cascade would not
bump or publish posthog-js, and the rebuild fix (bundled into the browser SDK
at build time) would never ship. Retarget the changeset at posthog-js, matching
the convention every other browser-SDK changeset already follows.

Generated-By: PostHog Desktop
Task-Id: b70c9594-d617-4924-9264-39b41fe39eaa
@github-actions

Copy link
Copy Markdown
Contributor
⚠️ Possible changeset mismatch — 1 undeclared, 1 extra

This is informational — the PR is not blocked. Click the triangle above to collapse, or push a fix and this comment will auto-delete.

Modified in this PR but not in any changeset:

  • @posthog/rrweb-snapshot

If this package should ship the change, add it to the changeset frontmatter:

---
"@posthog/rrweb-snapshot": patch
---

Declared in a changeset but no source files modified:

  • posthog-js

Double-check this is intentional — for example, releasing a previously-merged change.

Changesets in this PR:

  • posthog-js — patch

@dustinbyrne
dustinbyrne requested a review from a team September 1, 2026 13:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants