From 976136e38221a17fcc96f03940b9f8000b64a61f Mon Sep 17 00:00:00 2001 From: tengtian Date: Wed, 15 Apr 2026 20:10:09 +0200 Subject: [PATCH 1/2] fix: reject invalid dotted-decimal in hostname_rfc1123 validation RFC 1123 states that a valid hostname can never have the dotted-decimal form #.#.#.# since the highest-level label will be alphabetic. Strings like "277.168.0.1" were incorrectly accepted because the regex allows all-numeric labels. Now hostname_rfc1123 rejects dotted-decimal strings that are not valid IPv4 addresses. Valid IPv4 addresses like "192.168.0.1" continue to pass since they are legitimate host identifiers. Fixes #1561 --- baked_in.go | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/baked_in.go b/baked_in.go index abb5cfe04..b4c9fb0a1 100644 --- a/baked_in.go +++ b/baked_in.go @@ -2798,8 +2798,33 @@ func isHostnameRFC952(fl FieldLevel) bool { return hostnameRegexRFC952().MatchString(fl.Field().String()) } +// looksLikeDottedDecimal returns true if s looks like a dotted-decimal address +// (e.g. "277.168.0.1") — composed entirely of digits and dots, with at least one dot. +func looksLikeDottedDecimal(s string) bool { + hasDot := false + for _, c := range s { + if c == '.' { + hasDot = true + } else if c < '0' || c > '9' { + return false + } + } + return hasDot +} + func isHostnameRFC1123(fl FieldLevel) bool { - return hostnameRegexRFC1123().MatchString(fl.Field().String()) + val := fl.Field().String() + if !hostnameRegexRFC1123().MatchString(val) { + return false + } + // RFC 1123 §2.1: "a valid host name can never have the dotted-decimal + // form #.#.#.#, since at least the highest-level component label will + // be alphabetic." Reject strings that look like dotted-decimal but are + // not valid IPv4 addresses (e.g. 277.168.0.1). + if net.ParseIP(val) == nil && looksLikeDottedDecimal(val) { + return false + } + return true } func isFQDN(fl FieldLevel) bool { From 5df2fdd2160ec350d38086bf89ba94099ffba213 Mon Sep 17 00:00:00 2001 From: Herrtian <70463940+Herrtian@users.noreply.github.com> Date: Fri, 22 May 2026 13:00:10 +0200 Subject: [PATCH 2/2] fix: narrow dotted decimal hostname check --- baked_in.go | 33 +++++++++++++++++++-------------- validator_test.go | 7 +++++++ 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/baked_in.go b/baked_in.go index b4c9fb0a1..b81d72eee 100644 --- a/baked_in.go +++ b/baked_in.go @@ -2798,18 +2798,26 @@ func isHostnameRFC952(fl FieldLevel) bool { return hostnameRegexRFC952().MatchString(fl.Field().String()) } -// looksLikeDottedDecimal returns true if s looks like a dotted-decimal address -// (e.g. "277.168.0.1") — composed entirely of digits and dots, with at least one dot. -func looksLikeDottedDecimal(s string) bool { - hasDot := false +func isDottedDecimalIPv4(s string) bool { + labels := 1 + labelLen := 0 + for _, c := range s { - if c == '.' { - hasDot = true - } else if c < '0' || c > '9' { + switch { + case c == '.': + if labelLen == 0 { + return false + } + labels++ + labelLen = 0 + case c >= '0' && c <= '9': + labelLen++ + default: return false } } - return hasDot + + return labels == 4 && labelLen > 0 } func isHostnameRFC1123(fl FieldLevel) bool { @@ -2817,12 +2825,9 @@ func isHostnameRFC1123(fl FieldLevel) bool { if !hostnameRegexRFC1123().MatchString(val) { return false } - // RFC 1123 §2.1: "a valid host name can never have the dotted-decimal - // form #.#.#.#, since at least the highest-level component label will - // be alphabetic." Reject strings that look like dotted-decimal but are - // not valid IPv4 addresses (e.g. 277.168.0.1). - if net.ParseIP(val) == nil && looksLikeDottedDecimal(val) { - return false + if isDottedDecimalIPv4(val) { + ip := net.ParseIP(val) + return ip != nil && ip.To4() != nil } return true } diff --git a/validator_test.go b/validator_test.go index 00eba5949..7e9d464db 100644 --- a/validator_test.go +++ b/validator_test.go @@ -10677,6 +10677,13 @@ func TestHostnameRFC1123Validation(t *testing.T) { {"example.", false}, {"test_example", false}, {"192.168.0.1", true}, + {"0.0.0.0", true}, + {"255.255.255.255", true}, + {"277.168.0.1", false}, + {"192.168.0.256", false}, + {"192.168.0.a", true}, + {"123.456", true}, + {"1.2.3", true}, {"email@example.com", false}, {"2001:cdba:0000:0000:0000:0000:3257:9652", false}, {"2001:cdba:0:0:0:0:3257:9652", false},