{"record":{"id":"4fdf96635383bcd6","repo":"Tencent/WeKnora","slug":"s-failed-ssrf-validation-w","errorCode":null,"errorMessage":"%s failed SSRF validation: %w","messagePattern":"(.+?) failed SSRF validation: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/parser_url_security.go","lineNumber":29,"sourceCode":"\t\"mineru_endpoint\",\n\t\"mineru_vlm_server_url\",\n\t\"odl_hybrid_url\",\n\t\"paddleocr_vl_endpoint\",\n\t\"paddleocr_vl_cloud_base_url\",\n}\n\n// validateParserEngineOverrideURLs validates every parser override that can\n// cause this process or the trusted DocReader service to make an outbound\n// request. Per-upload overrides are included because API callers can provide\n// the generic parser_engine_overrides map directly.\nfunc validateParserEngineOverrideURLs(overrides map[string]string) error {\n\tfor _, key := range parserOutboundURLKeys {\n\t\trawURL := strings.TrimSpace(overrides[key])\n\t\tif rawURL == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tif err := secutils.ValidateURLForSSRF(rawURL); err != nil {\n\t\t\treturn fmt.Errorf(\"%s failed SSRF validation: %w\", key, err)\n\t\t}\n\t}\n\treturn nil\n}\n","sourceCodeStart":11,"sourceCodeEnd":34,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/parser_url_security.go#L11-L34","documentation":"validateParserEngineOverrideURLs runs SSRF validation (secutils.ValidateURLForSSRF) on parser engine override URLs for each known outbound URL key. If a configured override URL fails SSRF checks (private/loopback/link-local addresses, disallowed schemes), it is rejected with this message naming the offending key.","triggerScenarios":"convert (or the config-validation path) receiving parser overrides where a key like an outbound URL contains http://localhost, 127.0.0.1, 169.254.169.254, 10.x/192.168.x addresses, or file:/other non-http schemes.","commonSituations":"Self-hosted setups pointing a parser engine at an internal service URL (localhost:8080) which the SSRF guard blocks; typos like 'htp://' or missing scheme; copying internal K8s service DNS into tenant-facing config; cloud metadata endpoint URLs pasted by mistake.","solutions":["Replace the override URL with a publicly reachable HTTPS endpoint that passes SSRF validation.","If the target is legitimately internal, deploy an allowlist mechanism or run the validator with an approved internal-range policy instead of bypassing checks.","Fix the scheme/typos: URLs must be absolute http(s) with a resolvable public host.","Remove the empty/invalid override key so validation skips it."],"exampleFix":"// before\noverrides[\"pdf_engine_url\"] = \"http://127.0.0.1:8080/parse\"\n// after\noverrides[\"pdf_engine_url\"] = \"https://parser.example.com/parse\"","handlingStrategy":"validation","validationCode":"u, err := url.Parse(rawURL)\nif err != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") { return fmt.Errorf(\"invalid override URL\") }\nif host := u.Hostname(); isPrivateOrLoopback(host) { return fmt.Errorf(\"override URL must be public\") }","typeGuard":"func isPublicHTTPURL(raw string) bool {\n    u, err := url.Parse(raw)\n    if err != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") || u.Hostname() == \"\" { return false }\n    ip := net.ParseIP(u.Hostname())\n    return ip == nil || ip.IsPublic()\n}","tryCatchPattern":"if err := validateParserEngineOverrideURLs(overrides); err != nil {\n    // message names the offending key: reject that config field with 400\n    return fmt.Errorf(\"bad parser config: %w\", err)\n}","preventionTips":["Never point parser overrides at localhost/private ranges in shared environments","Use absolute https:// URLs with public hostnames","Validate override configs at save time, not only at request time","Maintain an allowlist for legitimately internal parser endpoints"],"tags":["ssrf","security","validation","url"],"backgroundTag":"ssrf-validation-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}