{"record":{"id":"ac0b54fddc351c81","repo":"Tencent/WeKnora","slug":"wildcard-entry-q-is-missing-a-domain-use-examp","errorCode":null,"errorMessage":"wildcard entry %q is missing a domain (use *.example.com)","messagePattern":"wildcard entry %q is missing a domain \\(use \\*\\.example\\.com\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/utils/security.go","lineNumber":1036,"sourceCode":"//   - \"*.<domain>\" must have a non-empty domain after the prefix\n//   - mid-string \"*\" is not supported\n//   - everything else is treated as an exact host or literal IP\n//     (we don't pre-resolve DNS here; that's a runtime concern)\nfunc ValidateSSRFWhitelistEntries(entries []string) error {\n\tfor _, entry := range entries {\n\t\tentry = strings.TrimSpace(entry)\n\t\tif entry == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tif strings.Contains(entry, \"/\") {\n\t\t\tif _, _, err := net.ParseCIDR(entry); err != nil {\n\t\t\t\treturn fmt.Errorf(\"invalid CIDR %q: %w\", entry, err)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif strings.HasPrefix(entry, \"*.\") {\n\t\t\tif len(entry) <= 2 {\n\t\t\t\treturn fmt.Errorf(\"wildcard entry %q is missing a domain (use *.example.com)\", entry)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif strings.Contains(entry, \"*\") {\n\t\t\treturn fmt.Errorf(\"wildcard pattern %q is not supported (only the \\\"*.\\\" prefix is allowed)\", entry)\n\t\t}\n\t}\n\treturn nil\n}\n\n// mergeSSRFWhitelistRaws joins two comma-separated raw strings, dropping\n// the comma when one side is empty. Exposed for the service layer's\n// \"merge SSRF_WHITELIST_EXTRA into the DB-backed list\" code path.\nfunc mergeSSRFWhitelistRaws(primary, extra string) string {\n\tprimary = strings.TrimSpace(primary)\n\textra = strings.TrimSpace(extra)\n\tswitch {\n\tcase primary == \"\" && extra == \"\":","sourceCodeStart":1018,"sourceCodeEnd":1054,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/utils/security.go#L1018-L1054","documentation":"ValidateSSRFWhitelistEntries requires wildcard entries to take the form '*.domain'. An entry starting with '*.' but with no actual domain after it (total length <= 2, i.e. exactly '*' or '*.') is rejected because it would match nothing or everything ambiguously. This is a config-shape guard, not a runtime network failure.","triggerScenarios":"A whitelist entry is exactly '*' or '*.' — e.g. someone wrote '*.' intending 'allow all subdomains' but forgot the domain, or a template variable like '*.${DOMAIN}' expanded empty.","commonSituations":"Env-var templating where the domain variable is unset, copy-paste truncation of '*.example.com', or an operator attempting a catch-all wildcard by entering '*' alone.","solutions":["Complete the wildcard entry with a real domain: '*.example.com' instead of '*.'","If a catch-all was intended, list explicit domains/CIDRs instead — the parser deliberately forbids bare '*'","Check that the env var/config substitution feeding the whitelist actually resolves (e.g. ${DOMAIN} is set)","Trim stray whitespace before the entry so it is not mangled during splitting"],"exampleFix":"// before\nSSRF_WHITELIST=*.\n// after\nSSRF_WHITELIST=*.example.com","handlingStrategy":"validation","validationCode":"e := strings.TrimSpace(entry)\nif strings.HasPrefix(e, \"*.\") && len(e) <= 2 {\n    return fmt.Errorf(\"wildcard %q missing domain\", e)\n}","typeGuard":"func isValidWildcard(entry string) bool {\n    return strings.HasPrefix(entry, \"*.\") && len(entry) > len(\"*.x\")\n}","tryCatchPattern":null,"preventionTips":["Never write '*.' or '*' alone in whitelist configs","Use templated configs with required-variable checks so *.${DOMAIN} fails loudly when DOMAIN is unset","Add a config-lint step in CI that runs ValidateSSRFWhitelistEntries on deploy values"],"tags":["ssrf","wildcard","configuration","validation"],"backgroundTag":"invalid-wildcard-pattern","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}