{"id":"5895dd5765407784","repo":"gofiber/fiber","slug":"hostauthorization-invalid-host-host-subdomai","errorCode":null,"errorMessage":"hostauthorization: invalid host ${host} — subdomain wildcards use the \"*.example.com\" form","messagePattern":"hostauthorization: invalid host (.+?) — subdomain wildcards use the \"\\*\\.example\\.com\" form","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"middleware/hostauthorization/hostauthorization.go","lineNumber":41,"sourceCode":"}\n\n// parseAllowedHosts splits AllowedHosts into exact and wildcard groups,\n// normalizing entries (port strip, lowercase, IDN→Punycode) and enforcing\n// RFC 1035 length limits. Panics on misconfiguration so it surfaces at startup.\nfunc parseAllowedHosts(hosts []string) parsedHosts {\n\tparsed := parsedHosts{\n\t\texact: make(map[string]struct{}, len(hosts)),\n\t}\n\n\tfor _, h := range hosts {\n\t\th = utils.TrimSpace(h)\n\t\tif h == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Reject the leading-dot form some other tools use; we want \"*.example.com\".\n\t\tif len(h) > 1 && h[0] == '.' {\n\t\t\tpanic(\"hostauthorization: invalid host \" + h + \" — subdomain wildcards use the \\\"*.example.com\\\" form\")\n\t\t}\n\n\t\tisWildcard := strings.HasPrefix(h, \"*.\")\n\t\tif isWildcard {\n\t\t\th = h[2:]\n\t\t}\n\n\t\th = normalizeHost(h)\n\t\tif h == \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\tvalidateHostLength(h)\n\n\t\tif isWildcard {\n\t\t\t// Stored with leading dot so the hot-path HasSuffix check stays alloc-free.\n\t\t\tparsed.wildcardSuffixes = append(parsed.wildcardSuffixes, \".\"+h)\n\t\t} else {","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/middleware/hostauthorization/hostauthorization.go#L23-L59","documentation":"Some tools (e.g. Django's ALLOWED_HOSTS) accept a leading-dot form like \".example.com\" to mean subdomains. This middleware requires the explicit \"*.example.com\" wildcard syntax for subdomain matching and rejects leading-dot entries (hostauthorization.go:40-42) to avoid ambiguity about whether the apex domain is included.","triggerScenarios":"Passing AllowedHosts entries such as \".example.com\" (leading dot). The apex domain must be listed separately because \"*.example.com\" matches subdomains only.","commonSituations":"Porting an allowed-hosts list from another framework that uses leading-dot syntax, or assuming the leading dot matches the bare domain.","solutions":["Rewrite leading-dot entries as \"*.example.com\" for subdomain matching.","If you also need the apex domain, list it separately: []string{\"example.com\", \"*.example.com\"}.","Audit lists migrated from Nginx/Django configs for leading-dot entries."],"exampleFix":"// before\nhostauthorization.Config{AllowedHosts: []string{\".example.com\"}}\n\n// after\nhostauthorization.Config{AllowedHosts: []string{\"example.com\", \"*.example.com\"}}","handlingStrategy":"validation","validationCode":"func normalizeAllowedHostsSyntax(hosts []string) ([]string, error) {\n    out := make([]string, 0, len(hosts))\n    for _, h := range hosts {\n        if strings.HasPrefix(h, \".\") {\n            return nil, fmt.Errorf(\"host %q uses leading-dot form; use %q instead\", h, \"*\"+h)\n        }\n        out = append(out, h)\n    }\n    return out, nil\n}\n\nhosts, err := normalizeAllowedHostsSyntax(cfg.AllowedHosts)\nif err != nil { log.Fatal(err) }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When migrating from other frameworks, audit for leading-dot entries.","List apex and wildcard subdomains separately to be explicit."],"tags":["hostauthorization","security","wildcard","config","dns","panic"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}