Skip to content

fix(security): resolve js/polynomial-redos in _.trim (CodeQL #161) - #627

Closed
scotmatson wants to merge 1 commit into
masterfrom
fix/js-polynomial-redos-trim
Closed

fix(security): resolve js/polynomial-redos in _.trim (CodeQL #161)#627
scotmatson wants to merge 1 commit into
masterfrom
fix/js-polynomial-redos-trim

Conversation

@scotmatson

Copy link
Copy Markdown
Contributor

What & why

CodeQL alert #161 (js/polynomial-redos, high) flags the _.trim polyfill in src/utils.js:

str.replace(/^[\s\xA0]+|[\s\xA0]+$/g, '')

The anchored-alternation regex backtracks in O(n²) on a long run of \t followed by a non-space. This is reachable from attacker-influenceable input: autocapture passes element textContent through _.trim (src/autocapture/utils.js).

Change

Replace it with native String.prototype.trim().

  • Behavior is identical. Native trim() strips exactly the ECMAScript WhiteSpace + LineTerminator set, which includes NBSP (\xA0) and BOM () — the same characters the old regex targeted — in linear time.
  • No new browser-support assumption. The codebase already calls native .trim() in src/autocapture/utils.js and src/recorder/session-recording.js.
  • Source-only change; no product/behavior change.

Testing

  • npm run lint — clean
  • npm run unit-test686 passing, 0 failing
  • New _.trim unit suite (5 tests): whitespace handling, interior preservation, \xA0/ equivalence to the former regex, all-whitespace input, and a linear-time guard (200k \t) that fails if a super-linear implementation ever regresses.

Impact

Resolves CodeQL #161. Since dist/ is rebuilt from src/ at release time, the corresponding dist/* alert clears on the next release rebuild.

🤖 Generated with Claude Code

Replace the MDN trim polyfill's anchored-alternation regex
(/^[\s\xA0]+|[\s\xA0]+$/g) with native String.prototype.trim.
CodeQL flagged the regex as polynomial ReDoS: on attacker-influenceable DOM
text (autocapture reads element textContent through _.trim) a long run of
'\t' followed by a non-space forces O(n^2) backtracking.

Native trim strips the identical set (ECMAScript WhiteSpace + LineTerminator,
including NBSP \xA0 and BOM ) in linear time, so behavior is unchanged.
The codebase already relies on native .trim() in autocapture/utils.js and
recorder/session-recording.js, so this adds no new browser-support assumption.

Adds a _.trim unit suite covering whitespace handling, \xA0/
equivalence to the former regex, and a linear-time guard against regression.

Resolves CodeQL alert #161 (js/polynomial-redos). The dist/ alert clears at
the next release rebuild, since dist is regenerated from src at release time.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@scotmatson

Copy link
Copy Markdown
Contributor Author

Moving this to the private repo at Jakub's request — superseded by mixpanel/mixpanel-js-private#482 (identical diff; private and public master are the same commit). Closing to avoid duplicate review.

@scotmatson scotmatson closed this 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