Skip to content

fix: close privacy detector ReDoS and CSS capture gaps - #1

Merged
roggernaut merged 6 commits into
mainfrom
cursor/ultrareview-privacy-detectors-7b83
Aug 25, 2026
Merged

fix: close privacy detector ReDoS and CSS capture gaps#1
roggernaut merged 6 commits into
mainfrom
cursor/ultrareview-privacy-detectors-7b83

Conversation

@roggernaut

@roggernaut roggernaut commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Summary

Follow-up to feat: harden privacy detectors (f43e30b) plus the ultrareview fixes. Based on latest rrweb-io/rrweb main (37a946a / npm 2.1.1 plus two later docs/vite commits).

Detector hardening

  • Reject nested quantifiers including {n,m} and ?, lookaround, named groups/\k, too many quantifiers, and inverted min/max lengths.
  • Apply capture policies to style text, _cssText, inline style, styleDiff, and stylesheet mutations.
  • Align the policy schema with runtime limits; match emails with more than four domain labels.

Heuristic PII as a plugin

Highlight-style fuzzy auto-detection (email, phone, Luhn card, SSN-like, IPv4) is no longer implied by balanced or strict. Those presets still mask form values and honor data-privacy / rules.

Opt in with:

import { getRecordPrivacyDetectorsPlugin } from '@rrweb/rrweb-plugin-privacy-detectors';

record({
  privacyPolicy: { version: 1, preset: 'balanced' },
  plugins: [getRecordPrivacyDetectorsPlugin()],
});

Or applyPrivacyDetectors(policy) for snapshot-only use. Policy flags still win over plugin defaults (detectors: { email: false }). Omitting privacyPolicy while loading the plugin keeps the legacy preset.

CI / compatibility fixes

  • Walk privacy ancestors with untainted parentElement / getRootNode.
  • Read tagName through the native getter when a form control is named tagName.
  • Apply plugin-transformed policy to the initial FullSnapshot, not only mutations.
  • Mask adopted stylesheet rules under the compiled policy.
  • Keep the @rrweb/record ESM bundle at least 185 KiB below the pre-treeshake baseline.

Test plan

  • Snapshot privacy tests (form tagName shadowing, hijacked getRootNode)
  • Detector plugin tests (balanced opt-in, omitted policy stays legacy)
  • Recorder test: plugin detectors apply to the initial FullSnapshot
  • Adopted stylesheet PII masking
  • CI on df6baa8 (12/12 green)
Open in Web Open in Cursor 

Rogier Trimpe and others added 5 commits August 25, 2026 10:23
Reject nested and high-quantifier custom regexes, lookaround, and named
backreferences at compile time. Apply capture policies to style text,
_cssText, inline style, and stylesheet mutations, and keep the policy
schema aligned with runtime limits.

Co-authored-by: Rogier Trimpe <roggernaut@users.noreply.github.com>
Stop enabling email/phone/card/SSN/IP detectors from balanced and strict
presets. Add @rrweb/rrweb-plugin-privacy-detectors and applyPrivacyDetectors
so Highlight-style fuzzy auto-detection is explicit.

Co-authored-by: Rogier Trimpe <roggernaut@users.noreply.github.com>
Privacy ancestor walks now use untainted DOM accessors so monkey-patched
getRootNode cannot abort snapshots. Named form controls that shadow
tagName no longer crash serialize/mask, and the record ESM size budget
is updated for the privacy-at-capture path.

Co-authored-by: Rogier Trimpe <roggernaut@users.noreply.github.com>
@cursor
cursor Bot changed the base branch from prototype/privacy-at-capture to main August 25, 2026 12:47
Pass the plugin-transformed policy into snapshot() so detector plugins
mask the initial FullSnapshot, not only later mutations. Keep an omitted
privacyPolicy on the legacy preset, mask adopted stylesheet rules, and
declare @rrweb/types on the detectors plugin.

Co-authored-by: Rogier Trimpe <roggernaut@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

Bundle Size Changes

Size change: +978.40 kB (+9.38%) | Total size: 11404.20 kB

all 🔍 - 1975.30 kB -> 2097.53 kB (+122.23 kB (+6.19%))
File Base PR Diff
all.cjs 567.78 kB 602.86 kB +35.08 kB (+6.18%) 🔍
all.js 567.45 kB 602.53 kB +35.08 kB (+6.18%) 🔍
all.umd.cjs 570.99 kB 606.18 kB +35.19 kB (+6.16%) 🔍
all.umd.min.cjs 269.09 kB 285.97 kB +16.88 kB (+6.27%) 🔍
browser-client 🔍 - 669.93 kB -> 792.00 kB (+122.07 kB (+18.22%))
File Base PR Diff
browser-client.cjs 192.10 kB 227.12 kB +35.02 kB (+18.23%) 🔍
browser-client.js 191.87 kB 226.89 kB +35.02 kB (+18.25%) 🔍
browser-client.umd.cjs 194.92 kB 230.07 kB +35.15 kB (+18.03%) 🔍
browser-client.umd.min.cjs 91.05 kB 107.93 kB +16.88 kB (+18.54%) 🔍
plugins 🆕 - 0 B -> 393.01 kB (+393.01 kB)
File Base PR Diff
packages/plugins/rrweb-plugin-privacy-detectors/dist/rrweb-plugin-privacy-detectors.cjs - 112.73 kB +112.73 kB 🆕
packages/plugins/rrweb-plugin-privacy-detectors/dist/rrweb-plugin-privacy-detectors.js - 112.54 kB +112.54 kB 🆕
packages/plugins/rrweb-plugin-privacy-detectors/dist/rrweb-plugin-privacy-detectors.umd.cjs - 115.20 kB +115.20 kB 🆕
packages/plugins/rrweb-plugin-privacy-detectors/dist/rrweb-plugin-privacy-detectors.umd.min.cjs - 52.54 kB +52.54 kB 🆕
record 🔍 - 552.55 kB -> 673.95 kB (+121.40 kB (+21.97%))
File Base PR Diff
record.cjs 158.41 kB 193.42 kB +35.00 kB (+22.10%) 🔍
record.js 158.32 kB 193.33 kB +35.00 kB (+22.11%) 🔍
record.umd.cjs 159.74 kB 194.42 kB +34.68 kB (+21.71%) 🔍
record.umd.min.cjs 76.07 kB 92.78 kB +16.71 kB (+21.97%) 🔍
replay - 1407.10 kB -> 1410.87 kB (+3.76 kB (+0.27%))
File Base PR Diff
replay.cjs 403.84 kB 404.79 kB +970 B (+0.23%)
replay.js 403.75 kB 404.69 kB +970 B (+0.23%)
replay.umd.cjs 406.82 kB 407.77 kB +970 B (+0.23%)
replay.umd.min.cjs 192.70 kB 193.63 kB +945 B (+0.48%)
rrweb 🔍 - 1913.48 kB -> 2035.68 kB (+122.21 kB (+6.39%))
File Base PR Diff
rrweb.cjs 550.94 kB 586.01 kB +35.07 kB (+6.37%) 🔍
rrweb.js 550.64 kB 585.71 kB +35.07 kB (+6.37%) 🔍
rrweb.umd.cjs 552.16 kB 587.33 kB +35.17 kB (+6.37%) 🔍
rrweb.umd.min.cjs 259.74 kB 276.63 kB +16.89 kB (+6.50%) 🔍
rrweb-player - 1643.88 kB -> 1647.64 kB (+3.76 kB (+0.23%))
File Base PR Diff
rrweb-player.cjs 473.37 kB 474.31 kB +970 B (+0.20%)
rrweb-player.js 473.24 kB 474.19 kB +970 B (+0.20%)
rrweb-player.umd.cjs 476.16 kB 477.11 kB +970 B (+0.20%)
rrweb-player.umd.min.cjs 221.11 kB 222.03 kB +945 B (+0.42%)
rrweb-snapshot 🔍 - 609.57 kB -> 699.51 kB (+89.94 kB (+14.76%))
File Base PR Diff
rrweb-snapshot.cjs 175.01 kB 200.88 kB +25.86 kB (+14.78%) 🔍
rrweb-snapshot.js 174.07 kB 199.54 kB +25.47 kB (+14.63%) 🔍
rrweb-snapshot.umd.cjs 177.48 kB 203.48 kB +26.00 kB (+14.65%) 🔍
rrweb-snapshot.umd.min.cjs 83.00 kB 95.61 kB +12.61 kB (+15.20%) 🔍

@roggernaut
roggernaut marked this pull request as ready for review August 25, 2026 15:11
@roggernaut
roggernaut merged commit 41c2282 into main Aug 25, 2026
12 checks passed
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.

2 participants