Skip to content

Validate domain hostname rules per label - #320

Open
gaoflow wants to merge 1 commit into
micke:mainfrom
gaoflow:fix-per-label-domain-validation
Open

Validate domain hostname rules per label#320
gaoflow wants to merge 1 commit into
micke:mainfrom
gaoflow:fix-per-label-domain-validation

Conversation

@gaoflow

@gaoflow gaoflow commented Jul 29, 2026

Copy link
Copy Markdown

valid_domain? checks the hostname rules positionally against the whole domain string instead of per label. It rejects a leading hyphen only via start_with?('-') (first label only) and a trailing hyphen only via include?('-.') (a hyphen followed by a dot, i.e. non-final labels only), and it has no length check at all. So the mirror positions leak through:

ValidEmail2::Address.new("user@foo.-bar.com").valid?  # => true  (leading hyphen, later label)
ValidEmail2::Address.new("user@example.com-").valid?  # => true  (trailing hyphen, final label)
ValidEmail2::Address.new("user@#{'a' * 64}.com").valid?  # => true  (label > 63 octets)
ValidEmail2::Address.new("user@#{(['a'] * 127).join('.')}a").valid?  # => true  (domain > 253 octets)

The spec already asserts that a domain may not begin or end with a dash ("is invalid if the domain begins with a dash" / "...ends with a dash"). These are the same rule applied to every label rather than only the first and last position of the domain string, plus the RFC 1035 length limits (63 per label, 253 total). Python's email_validator rejects all four shapes.

The fix splits the domain on . and validates each label (1–63 octets, no leading or trailing hyphen) plus the overall 253-octet limit. Internal hyphens, double hyphens (a--b) and punycode labels (xn--bcher-kva) stay valid — only the boundary positions of each label are checked, so no legitimate hostname is affected.

This is scoped to label structure and length; it does not touch PROHIBITED_DOMAIN_CHARACTERS_REGEX (the separate character-set surface). It uses the existing string/regex approach rather than a full IDNA library — labels are counted in characters, which matches how the rest of valid_domain? already works.

Tests: added a parametrized table of the malformed shapes (invalid) alongside the internal-hyphen / double-hyphen / punycode / 63-octet / 253-octet cases that must stay valid. Full suite green (bundle exec rake).

valid_domain? enforced hostname rules positionally across the whole
domain string (start_with?('-'), include?('-.'), and no length check)
rather than per label, so the mirror positions leaked through:

  - a leading hyphen on any non-first label (foo@sub.-example.com)
  - a trailing hyphen on the final label   (foo@example.com-)
  - a label longer than 63 octets
  - a domain longer than 253 octets

all validated as true. The existing spec already asserts that a domain
may not begin or end with a dash; these were asymmetric gaps in that
same rule.

Split the domain on '.' and validate each label (1-63 octets, no
leading or trailing hyphen) plus the overall 253-octet limit. Internal
hyphens, double hyphens and punycode (xn--) labels stay valid.
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