Skip to content

Hardening pass: input validation, origin checks, and default-safe field behaviour — legacy/v2 - #740

Open
shengxi-gt wants to merge 14 commits into
LifeSG:legacy/v2from
shengxi-gt:clean/MOL-22453-v2
Open

shengxi-gt wants to merge 14 commits into
LifeSG:legacy/v2from
shengxi-gt:clean/MOL-22453-v2

Conversation

@shengxi-gt

@shengxi-gt shengxi-gt commented Sep 18, 2026

Copy link
Copy Markdown

Hardening pass — legacy/v2

Covers several hardening changes and default-safe behaviour updates across fields and shared utilities. One commit — review the diff directly since the changes span multiple independent areas with varying blast radius.

Same changes as the main branch PR, adapted for v2's codebase (Text instead of Typography, styled-components CSS interpolation instead of direct cssText).

⚠️ Breaking changes

Four changes alter default runtime behaviour unconditionally, no opt-out, for every existing schema as soon as this ships:

  1. Iframe postMessage origin check is now hard default-on. Messages from a mismatched origin are silently dropped.
  2. 1000-character cap on schema-authored regex input. Inputs longer than 1000 chars are treated as non-matching regardless of the actual pattern result. Affects matches, notMatches, and filenameMatches rules.
  3. MaskedField maxLength now defaults to 500 whenever maskRegex is set and no max/length rule already narrows it.
  4. Pattern strings not wrapped in /pattern/flags slashes are no longer silently skipped. They previously landed in a catch block and validation was skipped entirely (value always passed). The shared parsing helper now falls back to treating the whole string as a raw pattern and applies it — any schema relying on the old silent no-op will now get real validation applied.

Narrower breaking changes (only affect a consumer that relied on the specific permissive behaviour being fixed): stricter sanitize-html configuration may now strip attributes that previously passed through; the ButtonField URL scheme check may block non-standard schemes; custom modal style strings now have @import/url() stripped.

Changes covered

  • CI pipeline configuration hardened
  • sanitize-html configuration tightened in Text, FilterCheckbox, Popover
  • ButtonField link URLs now restricted to http/https/tel/mailto schemes
  • Iframe postMessage now validates origin by default
  • Location-field search query now escaped before use in RegExp
  • OTP state field documented as client-asserted (no code change)
  • Schema regex inputs now capped at 1000 characters
  • MaskedField maxLength defaults to 500 when maskRegex is set
  • Shared regex parsing helper introduced; unwrapped patterns now evaluated instead of silently skipped
  • Custom modal style strings now strip @import and url() references
  • ImageUpload matches rule no longer blocks valid submissions (pre-existing bug fix)

Test plan

  • Full Jest suite + eslint + tsc --noEmit pass on this branch.
  • Each change was individually verified at the time it was written.

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.

1 participant