{"record":{"id":"89206ce5d22e9f48","repo":"siyuan-note/siyuan","slug":"generated-image-url-must-use-https","errorCode":null,"errorMessage":"generated image URL must use HTTPS","messagePattern":"generated image URL must use HTTPS","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/util/openai.go","lineNumber":783,"sourceCode":"\t} else if result.URL != \"\" {\n\t\tdata, err = downloadGeneratedImage(requestCtx, result.URL)\n\t} else {\n\t\terr = errors.New(\"image model returned neither base64 data nor URL\")\n\t}\n\tif err != nil {\n\t\treturn GeneratedImage{}, err\n\t}\n\tmimeType, extension, err := ValidateGeneratedImage(data)\n\tif err != nil {\n\t\treturn GeneratedImage{}, err\n\t}\n\treturn GeneratedImage{Data: data, MIMEType: mimeType, Extension: extension, RevisedPrompt: result.RevisedPrompt}, nil\n}\n\nfunc downloadGeneratedImage(ctx context.Context, rawURL string) ([]byte, error) {\n\tparsed, err := url.Parse(rawURL)\n\tif err != nil || parsed.Scheme != \"https\" || parsed.Host == \"\" {\n\t\treturn nil, errors.New(\"generated image URL must use HTTPS\")\n\t}\n\tif err = CheckHostSSRF(parsed.Hostname()); err != nil {\n\t\treturn nil, err\n\t}\n\tclient := generatedImageHTTPClient()\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, rawURL, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode < 200 || resp.StatusCode >= 300 {\n\t\treturn nil, fmt.Errorf(\"download generated image failed with status %d\", resp.StatusCode)\n\t}\n\tif resp.ContentLength > maxGeneratedImageBytes {","sourceCodeStart":765,"sourceCodeEnd":801,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/util/openai.go#L765-L801","documentation":"Thrown by downloadGeneratedImage (kernel/util/openai.go:783) when url.Parse fails OR the parsed scheme is not exactly 'https' OR the host is empty. SiYuan refuses plaintext HTTP and host-less URLs for generated-image downloads as a baseline transport-security guard, before the SSRF check (CheckHostSSRF) runs.","triggerScenarios":"The image model returns a URL with scheme http://, ftp://, or a relative/malformed URL with no scheme; or url.Parse rejects the string. Also fires if a redirect target downgrades to http (caught again at the redirect hook, but this is the initial-parse guard).","commonSituations":"Older/self-hosted OpenAI-compatible provider returning http CDN URLs; provider CDN misconfigured to serve over http; proxy that rewrote https to http; provider returned a relative path by mistake.","solutions":["Confirm the provider/CDN is configured to serve image URLs over HTTPS end to end.","If you operate the provider, force https in the URL generator.","If only b64json is available from the provider, switch the request to ResponseFormat=b64_json to bypass the URL path entirely.","Avoid proxies/env (HTTPS_PROXY) that downgrade the scheme."],"exampleFix":"// before\nresult := response.Data[0]\nif result.URL != \"\" {\n    data, err = downloadGeneratedImage(requestCtx, result.URL)\n}\n\n// after (prefer b64json for providers known to return http URLs)\nresult := response.Data[0]\nif result.B64JSON != \"\" {\n    data, err = base64.StdEncoding.DecodeString(result.B64JSON)\n} else if u, perr := url.Parse(result.URL); perr == nil && u.Scheme == \"https\" && u.Host != \"\" {\n    data, err = downloadGeneratedImage(requestCtx, result.URL)\n} else {\n    err = fmt.Errorf(\"provider returned non-HTTPS image URL %q; enable b64_json\", result.URL)\n}","handlingStrategy":"validation","validationCode":"u, err := url.Parse(result.URL)\nif err != nil || u.Scheme != \"https\" || u.Host == \"\" {\n    // prefer b64_json delivery or refuse the URL\n    return fmt.Errorf(\"refusing non-HTTPS image URL %q\", result.URL)\n}","typeGuard":null,"tryCatchPattern":"data, err := downloadGeneratedImage(ctx, result.URL)\nif err != nil && strings.Contains(err.Error(), \"must use HTTPS\") {\n    // switch this provider to b64_json mode, or surface a config error\n    imageRequest.ResponseFormat = openai.CreateImageResponseFormatB64JSON\n    // ...re-issue CreateImage\n}\nif err != nil { return err }","preventionTips":["Prefer b64_json delivery from providers whose CDN you do not control.","Audit HTTPS_PROXY/HTTP_PROXY env vars that may rewrite schemes.","When self-hosting an OpenAI-compatible server, force https on the image CDN."],"tags":["openai","image-generation","security","https","ssrf","go"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}