{"record":{"id":"ae6c03f24b44e961","repo":"Tencent/WeKnora","slug":"url-rejected-by-ssrf-policy-w","errorCode":null,"errorMessage":"URL rejected by SSRF policy: %w","messagePattern":"URL rejected by SSRF policy: %w","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/utils/httputil.go","lineNumber":23,"sourceCode":"\t\"io\"\n\t\"net/http\"\n\t\"strings\"\n\t\"time\"\n)\n\nvar defaultHTTPClient = NewSSRFSafeHTTPClient(SSRFSafeHTTPClientConfig{\n\tTimeout:      60 * time.Second,\n\tMaxRedirects: 10,\n})\n\n// DownloadBytes fetches the content at the given HTTP(S) URL and returns the\n// raw bytes. It reuses a package-level http.Client with a 60-second timeout.\nfunc DownloadBytes(url string) ([]byte, error) {\n\tif !strings.HasPrefix(url, \"http://\") && !strings.HasPrefix(url, \"https://\") {\n\t\treturn nil, fmt.Errorf(\"unsupported URL scheme: %s\", url)\n\t}\n\tif err := ValidateURLForSSRF(url); err != nil {\n\t\treturn nil, fmt.Errorf(\"URL rejected by SSRF policy: %w\", err)\n\t}\n\tresp, err := defaultHTTPClient.Get(url)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"HTTP GET: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"HTTP %d for %s\", resp.StatusCode, url)\n\t}\n\tdata, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read body: %w\", err)\n\t}\n\treturn data, nil\n}\n","sourceCodeStart":5,"sourceCodeEnd":39,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/utils/httputil.go#L5-L39","documentation":"DownloadBytes runs every URL through ValidateURLForSSRF before fetching; if the SSRF policy rejects the target (private/loopback/link-local IPs, disallowed hosts, etc.) the error is wrapped as \"URL rejected by SSRF policy\". This protects against server-side request forgery against internal networks.","triggerScenarios":"Calling DownloadBytes with a URL that resolves to or points at a blocked target: localhost/127.0.0.1, 10.x/172.16.x/192.168.x private addresses, 169.254.x metadata endpoints, or any host denied by the SSRF policy.","commonSituations":"Fetching user-supplied webhook/avatar/import URLs that point at internal services, testing against a locally running server, misconfigured internal-only endpoints, or DNS rebinding to internal IPs.","solutions":["Use a public, externally reachable URL","If internal fetching is legitimately required, use an approved internal client that bypasses the SSRF guard, not DownloadBytes","Check ValidateURLForSSRF's exact policy and the wrapped inner error to see which rule fired","For local development, run the target on a public test endpoint or mock the HTTP layer"],"exampleFix":"// before\nDownloadBytes(\"http://localhost:8080/asset\")\n// after\nDownloadBytes(\"https://cdn.example.com/asset\")","handlingStrategy":"try-catch","validationCode":"u, err := url.Parse(raw)\nif err != nil { return err }\nip, err := net.LookupIP(u.Hostname())\nif err != nil { return err }\nfor _, a := range ip {\n    if a.IsLoopback() || a.IsPrivate() || a.IsLinkLocalUnicast() {\n        return fmt.Errorf(\"URL points at a blocked/internal address\")\n    }\n}","typeGuard":"func isPublicURL(raw string) bool {\n    u, err := url.Parse(raw)\n    if err != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") { return false }\n    ip, err := net.LookupIP(u.Hostname())\n    if err != nil { return false }\n    for _, a := range ip {\n        if a.IsLoopback() || a.IsPrivate() || a.IsLinkLocalUnicast() { return false }\n    }\n    return true\n}","tryCatchPattern":"data, err := DownloadBytes(url)\nif err != nil {\n    var ssrfErr *fmt.wrapError\n    if strings.Contains(err.Error(), \"URL rejected by SSRF policy\") {\n        // do NOT retry; the target is policy-blocked — use a public URL\n        return fmt.Errorf(\"target blocked: %w\", err)\n    }\n}","preventionTips":["Never fetch user-supplied URLs pointing at private/loopback ranges","Use public endpoints or an approved internal fetch path for internal resources","Log the inner SSRF-policy cause to diagnose which rule rejected the URL","Do not attempt retries against SSRF-rejected targets — retrying cannot succeed"],"tags":["security","ssrf","http","go"],"backgroundTag":"ssrf-blocked","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}