Skip to content

Reject empty labels in idn-hostname format - #1274

Merged
stevehu merged 4 commits into
networknt:masterfrom
dngr2:idn-hostname-reject-empty-labels
Aug 26, 2026
Merged

Reject empty labels in idn-hostname format#1274
stevehu merged 4 commits into
networknt:masterfrom
dngr2:idn-hostname-reject-empty-labels

Conversation

@dngr2

@dngr2 dngr2 commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

The idn-hostname format accepts host names with a leading or interior empty label:

".example"   // reported valid — should be invalid
"a..b"       // reported valid — should be invalid

RFC5892.isValid skips empty labels with continue, with a comment about a trailing .. But String.split already drops trailing empty strings, so the skip only ever hits a leading or interior empty label, both of which are invalid. Rejecting them matches the JSON-Schema-Test-Suite (idn-hostname.json: "leading dot" and "empty label between two dots is invalid") and the reference validator. Ordinary host names (and trailing dots) are unaffected; the full suite stays green (added a test).

RFC5892.isValid skipped empty labels with continue, so a leading or interior
empty label -- ".example" or "a..b" -- validated as a valid idn-hostname.
String.split already drops trailing empty labels, so the skip only ever hit
leading/interior empties, which are invalid. Reject them.
@stevehu
stevehu requested a lite review from Copilot August 20, 2026 16:31

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates idn-hostname format validation to reject hostnames containing leading or interior empty labels (e.g. .example, a..b), aligning behavior with the JSON-Schema-Test-Suite and reference validators.

Changes:

  • Change RFC5892.isValid to fail fast on empty labels produced by splitting hostnames into labels.
  • Add a unit test asserting .example and a..b are invalid while ordinary hostnames remain valid.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/main/java/com/networknt/schema/utils/RFC5892.java Tightens IDN hostname validation by rejecting empty labels during label iteration.
src/test/java/com/networknt/schema/FormatValidatorTest.java Adds regression coverage for invalid empty-label idn-hostname inputs and confirms valid hostnames still pass.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 107 to +111
for (String label : labels) {
if (label.isEmpty()) continue; // A DNS entry may contain a trailing '.'.
// String.split() drops trailing empty strings, so a trailing '.' never
// produces an empty label here. A leading or interior empty label
// (e.g. ".example" or "a..b") is invalid.
if (label.isEmpty()) return false;
Comment on lines +228 to +232
// A leading or interior empty label (a leading dot, or two adjacent dots) is invalid.
assertFalse(schema.validate("\".example\"", InputFormat.JSON,
ec -> ec.executionConfig(c -> c.formatAssertionsEnabled(true))).isEmpty());
assertFalse(schema.validate("\"a..b\"", InputFormat.JSON,
ec -> ec.executionConfig(c -> c.formatAssertionsEnabled(true))).isEmpty());
String.split returns an empty array for a value that is all separators
("..." or "。。"), so the loop was skipped and it validated as true. Reject
when there are no labels; this also subsumes the single-separator case.
@dngr2

dngr2 commented Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

Good catch. A value that is only separators (..., or 。。) splits to an empty array, so the loop was skipped and it fell through to valid. Pushed a guard that rejects when there are no labels — that also subsumes the earlier single-separator case, so I dropped that special check. Added the two inputs as regression tests alongside the existing empty-label ones.

@stevehu

stevehu commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

@stevehu stevehu closed this Aug 26, 2026
@stevehu stevehu reopened this Aug 26, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment on lines +108 to +110
// String.split() drops trailing empty strings, so a trailing '.' never
// produces an empty label here. A leading or interior empty label
// (e.g. ".example" or "a..b") is invalid.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (2)

Previously missed (1) — in code that hasn't changed since the last review.

src/test/java/com/networknt/schema/FormatValidatorTest.java:242

  • The new test exercises leading/interior empty labels, but it doesn’t cover the edge case where adjacent separators occur at the end (e.g. "a.."), which can be mishandled if the implementation drops trailing empty split tokens. Also, since the implementation explicitly allows a trailing separator, adding a regression assertion for a trailing-dot hostname (e.g. "example.") would lock in the intended behavior described in the PR.
        // A leading or interior empty label (a leading dot, or two adjacent dots) is invalid.
        assertFalse(schema.validate("\".example\"", InputFormat.JSON,
                ec -> ec.executionConfig(c -> c.formatAssertionsEnabled(true))).isEmpty());
        assertFalse(schema.validate("\"a..b\"", InputFormat.JSON,
                ec -> ec.executionConfig(c -> c.formatAssertionsEnabled(true))).isEmpty());

src/main/java/com/networknt/schema/utils/RFC5892.java:106

  • String.split(regex) with the default limit drops all trailing empty strings. That means inputs like "a.." (adjacent separators at the end) will be split to ["a"], so the new label.isEmpty() check never runs and the empty label is not rejected. To reliably detect empty labels while still allowing exactly one trailing separator, preserve trailing empties with split(..., -1) and explicitly ignore only a single final empty label.
        // RFC 5892 calls each segment in a host name a label. They are separated by all the recognized label separators.
        String[] labels = value.split(LABEL_SEPARATOR_REGEX);
        if (labels.length == 0) {
            return false; // a value made up only of label separators (e.g. "." or "...") has no labels
        }

@stevehu
stevehu merged commit a9c9638 into networknt:master Aug 26, 2026
3 checks passed
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.

3 participants