fix: add RFC 1035 length limits to domain regex#5970
Conversation
|
TL;DR — Aligns Key changes
Summary | 2 files | 1 commit | base: RFC 1035 length limits on
|
There was a problem hiding this comment.
Important
The regex change itself is correct and well-motivated — RFC 1035 interpretations are right, no ReDoS risk, no incidental narrowing beyond the documented limits. But tightening z.regexes.domain leaves two spots in the tree that embed the old regex literal and will now be inaccurate: the recommended-schema callout in packages/docs/content/api.mdx and an inline comment next to the consumer in this test file. Please update both before merge.
Note that z.regexes.domain is a public export and this is technically a breaking change, though the newly-rejected inputs (TLD >63 chars, total domain >253 chars) are all DNS-invalid by RFC 1035 — the same limits z.regexes.hostname already enforces — so the framing as a fix is reasonable. Worth a line in the eventual release notes.
Note: 1 inline comment(s) dropped because they did not anchor to lines inside the PR diff:
packages/zod/src/v4/classic/tests/string.test.ts:433(RIGHT) — line 433 (RIGHT) is not inside a diff hunk
Claude Opus | 𝕏
| /^(?=.{1,253}\.?$)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[-0-9a-zA-Z]{0,61}[0-9a-zA-Z])?)*\.?$/; | ||
|
|
||
| export const domain: RegExp = /^([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/; | ||
| export const domain: RegExp = /^(?=.{1,253}\.?$)([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,63}$/; |
There was a problem hiding this comment.
Consider a one-line annotation so the magic numbers are self-documenting, matching the style of the hostname comment above:
/** RFC 1035: labels ≤63 chars, total ≤253 chars, TLD 2–63 chars. */
export const domain: RegExp = /^(?=.{1,253}\.?$)([a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,63}$/;Not blocking — but would save a reader from deriving intent from the literals.
The domain regex (used by z.httpUrl()) was missing length anchors that
the hostname regex already enforces:
- No 253-character total length limit
- No upper bound on TLD label length
Added:
- (?=.{1,253}\.?$) lookahead for overall domain length
- {2,63} TLD label cap (was unbounded {2,})
Fixes colinhacks#5965
d54ecd6 to
1072064
Compare
There was a problem hiding this comment.
Reviewed changes — added two test cases exercising the new RFC 1035 length limits on z.regexes.domain.
- TLD >63 chars rejected —
http://example.+ 64-char label triggers the{2,63}TLD cap. - Domain >253 chars rejected — 259-char hostname triggers the
(?=.{1,253}\.?$)lookahead.
The two items flagged in the prior review (packages/docs/content/api.mdx:382 embedded regex literal and packages/zod/src/v4/classic/tests/string.test.ts:433 stale regex comment) remain unaddressed — both still show the pre-change pattern.
DeepSeek Pro (free via Pullfrog for OSS) | 𝕏
Problem
The
regexes.domainregex (used internally byz.httpUrl()for hostname validation) was missing RFC 1035 length limits that theregexes.hostnameregex already enforces:{2,}vs{2,63})This meant
z.httpUrl()accepted domains exceeding the 253-character DNS limit and TLDs longer than 63 characters, whilez.hostname()correctly rejected them.Fix
Added RFC 1035 length constraints to
regexes.domain:(?=.{1,253}\.?$)lookahead — enforces the 253-character total domain length limit{2,63}on the TLD label — caps the last label at 63 characters per RFC 1035Testing
Fixes #5965