{"record":{"id":"0ffb7e250b054e6a","repo":"Tencent/WeKnora","slug":"blocked-by-ssrf-policy-w","errorCode":null,"errorMessage":"blocked by SSRF policy: %w","messagePattern":"blocked by SSRF policy: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/docparser/image_resolver.go","lineNumber":786,"sourceCode":"\n// fetchAndStoreRemoteImage applies the SSRF policy, downloads the image,\n// rejects icons and uploads the bytes to storage.\n//\n// Both the Markdown and the HTML scan go through here so that the SSRF check,\n// the icon filter and the whitelist behaviour cannot drift apart between the\n// two syntaxes.\nfunc fetchAndStoreRemoteImage(\n\tctx context.Context,\n\tclient *http.Client,\n\tfileSvc interfaces.FileService,\n\ttenantID uint64,\n\timgURL string,\n) (*remoteImageResult, error) {\n\twhitelisted := isWhitelistedImageHost(imgURL)\n\n\tif !whitelisted {\n\t\tif err := secutils.ValidateURLForSSRF(imgURL); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"blocked by SSRF policy: %w\", err)\n\t\t}\n\t}\n\n\tdata, mimeType, err := downloadImage(ctx, client, imgURL)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"download: %w\", err)\n\t}\n\n\tif isIconImage(data) {\n\t\treturn nil, errRemoteImageIsIcon\n\t}\n\n\tif whitelisted {\n\t\treturn &remoteImageResult{MimeType: mimeType, KeepOriginalURL: true}, nil\n\t}\n\n\text := extFromMime(mimeType)\n\tif ext == \"\" {","sourceCodeStart":768,"sourceCodeEnd":804,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/docparser/image_resolver.go#L768-L804","documentation":"This error is returned when fetching a remote image is blocked because the target URL fails SSRF (server-side request forgery) validation. Whitelisted image hosts skip the check; all other URLs must pass secutils.ValidateURLForSSRF, which rejects private/loopback/link-local IPs and disallowed schemes. This is a deliberate security control, not an incidental failure.","triggerScenarios":"fetchAndStoreRemoteImage called with an imgURL whose host is not whitelisted and which resolves to a private/loopback/metadata IP, uses a non-http(s) scheme, or is otherwise rejected by the SSRF validator.","commonSituations":"Documents containing images pointing at internal hosts (169.254.169.254, localhost, 10.x), file:// or other schemes, redirects to internal addresses, hosts not added to the whitelist.","solutions":["Check the URL: it must be a public http(s) address resolvable to a public IP","Add the trusted host to the image-host whitelist if it is legitimately required","Do not bypass the validator for user-supplied URLs (SSRF risk)","Test the exact URL with secutils.ValidateURLForSSRF to see the specific rejection reason"],"exampleFix":"// before\nimgURL := \"http://localhost:8080/logo.png\" // blocked\n// after\nimgURL := \"https://cdn.example.com/logo.png\" // public URL passes SSRF validation","handlingStrategy":"validation","validationCode":"u, err := url.Parse(imgURL)\nif err != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") {\n    return fmt.Errorf(\"reject non-http(s) url: %q\", imgURL)\n}\nips, err := net.LookupIP(u.Hostname())\nif err != nil { return err }\nfor _, ip := range ips {\n    if ip.IsLoopback() || ip.IsPrivate() || ip.IsLinkLocalUnicast() {\n        return fmt.Errorf(\"internal address not allowed: %v\", ip)\n    }\n}","typeGuard":null,"tryCatchPattern":"res, err := resolver.fetchAndStoreRemoteImage(ctx, imgURL, tenantID)\nif err != nil {\n    if strings.Contains(err.Error(), \"blocked by SSRF policy\") {\n        return fmt.Errorf(\"image url %q rejected by security policy: %w\", imgURL, err)\n    }\n    return err\n}","preventionTips":["Only allow public http(s) image URLs from user content","Maintain an explicit whitelist for trusted image hosts","Never bypass SSRF validation for dynamic/user-supplied URLs","Educate that blocks on 169.254.x / localhost are intentional security controls"],"tags":["ssrf","security","url-validation","image"],"backgroundTag":"ssrf-url-blocked","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}