{"record":{"id":"b2794bba5e1b5f74","repo":"chenhg5/cc-connect","slug":"redirected-to-unsupported-image-url","errorCode":null,"errorMessage":"redirected to unsupported image URL","messagePattern":"redirected to unsupported image URL","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"platform/feishu/feishu.go","lineNumber":6599,"sourceCode":"\nfunc fetchRichCardRemoteImage(ctx context.Context, rawURL string) ([]byte, string, error) {\n\tu, err := url.Parse(rawURL)\n\tif err != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") || u.Host == \"\" {\n\t\treturn nil, \"\", errors.New(\"invalid remote image URL\")\n\t}\n\n\tclient := &http.Client{\n\t\tTimeout: richCardImageFinalWait,\n\t\tTransport: &http.Transport{\n\t\t\tDialContext:           dialPublicRichCardImageContext,\n\t\t\tResponseHeaderTimeout: richCardImageFinalWait,\n\t\t},\n\t\tCheckRedirect: func(req *http.Request, via []*http.Request) error {\n\t\t\tif len(via) >= 3 {\n\t\t\t\treturn errors.New(\"too many redirects\")\n\t\t\t}\n\t\t\tif !isRemoteRichCardImageURL(req.URL.String()) {\n\t\t\t\treturn errors.New(\"redirected to unsupported image URL\")\n\t\t\t}\n\t\t\treturn nil\n\t\t},\n\t}\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, rawURL, nil)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\treq.Header.Set(\"User-Agent\", \"cc-connect-feishu-rich-card-image-resolver/1.0\")\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\tdefer func() {\n\t\tif err := resp.Body.Close(); err != nil {\n\t\t\tslog.Debug(\"feishu: close rich card image response body\", \"error\", err)","sourceCodeStart":6581,"sourceCodeEnd":6617,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/feishu/feishu.go#L6581-L6617","documentation":"This error is thrown by the Feishu platform's CheckRedirect hook on the HTTP client used to fetch remote images for rich cards. When the image URL redirects, every hop must still pass the isRemoteRichCardImageURL validation (http/https scheme, public host). If a redirect lands on a non-conforming URL — typically a private/internal IP, or a non-http(s) scheme — the client aborts with this error to block SSRF-style redirects.","triggerScenarios":"Occurs during rich-card image download when the remote server responds with a 3xx redirect whose Location points to a URL that fails isRemoteRichCardImageURL (e.g. redirects to a private IP like 127.0.0.1/10.x.x.x, or to file:// or another scheme), or after more than 3 hops (which yields 'too many redirects' instead).","commonSituations":"Configuring a card image URL pointing at an internal service or local dev server that redirects; image CDNs that redirect to signed internal storage URLs; misconfigured reverse proxies; deliberate SSRF attempts via redirect chains.","solutions":["Point the card image URL directly at a final, publicly reachable http(s) image URL instead of a redirector.","If the redirect target is legitimate, host the image on an approved public host that isRemoteRichCardImageURL accepts.","If this is your own server, fix the redirect so it lands on a public https URL, and keep the redirect chain to fewer than 3 hops.","Download the image yourself, verify it, and serve it from a trusted static host."],"exampleFix":"// before\nimageURL := \"http://internal.corp/logo\" // redirects to http://10.0.0.5/img\n// after\nimageURL := \"https://cdn.example.com/img/logo.png\" // direct public https image","handlingStrategy":"validation","validationCode":"u, err := url.Parse(imageURL)\nif err != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") || !isPublicHost(u.Hostname()) {\n    return fmt.Errorf(\"image URL will fail fetch validation: %s\", imageURL)\n}","typeGuard":null,"tryCatchPattern":"img, err := fetchRichCardImage(ctx, imageURL)\nif err != nil {\n    log.Warn(\"card image fetch failed; falling back to placeholder\", \"err\", err)\n    img = placeholderImage\n}","preventionTips":["Use final, direct public https image URLs, not redirectors","Never point card images at internal/localhost hosts","Keep redirect chains under 3 hops","Pre-host images on your own CDN instead of third-party redirect services"],"tags":["network","ssrf","http-redirect","feishu","image-download"],"backgroundTag":"invalid-url","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}