2d0a49e0d1c3f7e26bc83b31ba84ba5ba9418fd5
Pre-audit /api/v1/clients accepted:
- contacts[].value='not-an-email' with channel='email' → silent bounce
- fullName=' ' (whitespace-only) → blank-chip renders everywhere
- fullName='Hidden<ZWSP>Char<ZWSP>Name' (zero-width chars) → search blind spot
This commit:
1. New `humanTextSchema()` helper in src/lib/validators/text.ts that
strips invisible/bidi/control chars, trims, then length-checks.
2. `fullName` switched to `humanTextSchema({ min: 1, max: 200 })`.
3. `contactSchema` gains a `superRefine` requiring valid email format
when `channel === 'email'`.
Verified live:
- invalid email → 400 "Must be a valid email address." (field-scoped)
- whitespace name → 400 "Too small: expected string to have >=1 characters"
- zero-width chars → stored as cleaned "HiddenCharName"
- valid baseline → 201
Followup tasks (deferred): apply `humanTextSchema` to yachts/companies/
interests/notes/reminders names; audit render paths for XSS-via-stored-
HTML (default React escaping is safe; pdfme/email-merge surfaces need a
spot-check).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Description
No description provided
Languages
TypeScript
98.7%
HTML
1%
CSS
0.1%
Shell
0.1%