feat: Privacy at Capture — recorded-DOM URL sanitization (experimental) - #9
Open
roggernaut wants to merge 4 commits into
Open
feat: Privacy at Capture — recorded-DOM URL sanitization (experimental)#9roggernaut wants to merge 4 commits into
roggernaut wants to merge 4 commits into
Conversation
Bundle Size ChangesSize change: +39.54 kB (+0.36%) | Total size: 11069.58 kB
|
| File | Base | PR | Diff |
|---|---|---|---|
all.cjs |
603.81 kB | 606.13 kB | +2.32 kB (+0.38%) |
all.js |
603.48 kB | 605.80 kB | +2.32 kB (+0.38%) |
all.umd.cjs |
607.35 kB | 609.71 kB | +2.36 kB (+0.39%) |
all.umd.min.cjs |
286.41 kB | 287.54 kB | +1.13 kB (+0.39%) |
browser-client - 794.48 kB -> 802.59 kB (+8.11 kB (+1.02%))
| File | Base | PR | Diff |
|---|---|---|---|
browser-client.cjs |
227.78 kB | 230.09 kB | +2.31 kB (+1.01%) |
browser-client.js |
227.55 kB | 229.86 kB | +2.31 kB (+1.02%) |
browser-client.umd.cjs |
230.94 kB | 233.29 kB | +2.35 kB (+1.02%) |
browser-client.umd.min.cjs |
108.22 kB | 109.35 kB | +1.13 kB (+1.05%) |
record - 676.87 kB -> 684.98 kB (+8.10 kB (+1.20%))
| File | Base | PR | Diff |
|---|---|---|---|
record.cjs |
194.29 kB | 196.60 kB | +2.31 kB (+1.19%) |
record.js |
194.20 kB | 196.51 kB | +2.31 kB (+1.19%) |
record.umd.cjs |
195.31 kB | 197.66 kB | +2.35 kB (+1.20%) |
record.umd.min.cjs |
93.07 kB | 94.21 kB | +1.13 kB (+1.22%) |
rrweb - 2039.66 kB -> 2047.77 kB (+8.11 kB (+0.40%))
| File | Base | PR | Diff |
|---|---|---|---|
rrweb.cjs |
587.18 kB | 589.49 kB | +2.32 kB (+0.39%) |
rrweb.js |
586.88 kB | 589.19 kB | +2.32 kB (+0.39%) |
rrweb.umd.cjs |
588.52 kB | 590.87 kB | +2.35 kB (+0.40%) |
rrweb.umd.min.cjs |
277.09 kB | 278.22 kB | +1.13 kB (+0.41%) |
rrweb-snapshot - 702.08 kB -> 709.17 kB (+7.09 kB (+1.01%))
| File | Base | PR | Diff |
|---|---|---|---|
rrweb-snapshot.cjs |
201.81 kB | 203.80 kB | +1.99 kB (+0.99%) |
rrweb-snapshot.js |
200.40 kB | 202.35 kB | +1.95 kB (+0.97%) |
rrweb-snapshot.umd.cjs |
204.43 kB | 206.42 kB | +1.99 kB (+0.98%) |
rrweb-snapshot.umd.min.cjs |
95.45 kB | 96.61 kB | +1.16 kB (+1.21%) |
roggernaut
force-pushed
the
privacy-at-capture-url-sanitization
branch
from
September 2, 2026 14:33
ca4f14c to
7c1769d
Compare
roggernaut
force-pushed
the
privacy-at-capture-core
branch
from
September 2, 2026 19:51
ee793c7 to
da75a0f
Compare
roggernaut
force-pushed
the
privacy-at-capture-url-sanitization
branch
from
September 2, 2026 21:06
7c1769d to
11c2f29
Compare
…perimental) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…strict Add sanitizeMetaUrl (blocked-list-only param masking) for the Meta event's window.location.href call site in record/index.ts, so strict's mask-every-param-unless-allowlisted rule applies only to DOM URL attributes -- the Meta href is the recording's own address, not markup a page author wrote, so masking every one of its params (most apps' own routing state) would make strict useless for identifying which page a session happened on. Implemented as an internal paramsMode option on sanitizeUrl so the special case stays inside this layer; core has no sanitizeUrl branch. Flagged in guide.md and the changeset as an open design question for upstream. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…root-relative Sanitization parses against an internal base URL and re-serializes the path, so a relative URL in an attribute rrweb does not already absolutify (`<form action>`, `<video poster>`, ...) is recorded root-relative: `pay/confirm` becomes `/pay/confirm`. Behavior unchanged; this was undocumented. refactor(privacy): rename the `manual` preset to `minimal` throughout the url-sanitization layer's own additions -- the `sanitizeUrl` test fixtures and test names. Clean rename, nothing released; the record()-level "manual selector"/"manual half" test names are unrelated and untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
roggernaut
force-pushed
the
privacy-at-capture-url-sanitization
branch
from
September 3, 2026 10:26
11c2f29 to
cd0539b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Under
balancedandstrict, every URL-bearing attribute the serializer emits (action,background,data,formaction,href,poster,rr_src,src,xlink:href) and the Meta event'shrefgo throughsanitizeUrl:username/password) is strippedaccess_token,auth,code,key,password,secret,session,token) plus anything inurl.blockedQueryParametersis replaced with*url.removeHash: falsestrictblocks every parameter's value unlessurl.allowedQueryParametersnames it explicitlyParameter names stay visible so replays keep their routing context. An unparseable URL fails closed: the attribute is dropped (
null) rather than emptied, since an emptysrc/hrefre-resolves to the document URL at replay and actually gets requested. The unmask escape cannot reopen a sanitized URL.rr_src— the name the serializer gives a cross-origin<iframe src>it cannot see into — is in the URL attribute set, because the rename happens before finalization and the renamed attribute would otherwise escape the policy entirely.No vendor precedent — review this hardest
Unlike everything else in Privacy at Capture (#4), no session-replay vendor sanitizes URLs in the recorded DOM. PostHog, Highlight, Sentry, Amplitude and Mixpanel all record
hrefandsrcverbatim and scrub URLs in their ingestion pipeline instead, if at all. This is rrweb's own design rather than an established pattern, and it rewrites attribute values that the replay then depends on.This PR layers directly on #4 and is independent of the detectors PR (#8) — neither depends on the other's code.
Tests
packages/rrweb-snapshot— 231 passed, 1 skippedpackages/rrwebtest/record/privacy.test.ts+test/record.test.ts— passing headless (current counts in CI)npx tsc -bclean🤖 Generated with Claude Code