Tencent/WeKnora · error
jsonl URL blocked by SSRF check: %v
Error message
jsonl URL blocked by SSRF check: %v
What it means
fetchResults validates the JSONL result URL returned by the cloud service with utils.ValidateURLForSSRF before downloading. If the URL points at a private/loopback/link-local address or otherwise fails SSRF policy, the download is aborted with this error. This is an intentional security guard protecting the host network from a provider-controlled (or attacker-influenced) URL.
Source
Thrown at internal/infrastructure/docparser/paddleocr_vl_cloud_converter.go:266
return "", fmt.Errorf("task timed out after %d polls", pollCount)
}
// --- result parsing ---
type paddleOCRVLCloudResultLine struct {
Result struct {
LayoutParsingResults []struct {
Markdown struct {
Text string `json:"text"`
Images map[string]string `json:"images"`
} `json:"markdown"`
} `json:"layoutParsingResults"`
} `json:"result"`
}
func (c *PaddleOCRVLCloudReader) fetchResults(jsonlURL string) (string, map[string]string, error) {
if err := utils.ValidateURLForSSRF(jsonlURL); err != nil {
return "", nil, fmt.Errorf("jsonl URL blocked by SSRF check: %v", err)
}
client := utils.NewSSRFSafeHTTPClient(utils.SSRFSafeHTTPClientConfig{Timeout: 120 * time.Second, MaxRedirects: 5})
resp, err := client.Get(jsonlURL)
if err != nil {
return "", nil, fmt.Errorf("download jsonl: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", nil, fmt.Errorf("download jsonl status %d", resp.StatusCode)
}
data, err := io.ReadAll(resp.Body)
if err != nil {
return "", nil, fmt.Errorf("read jsonl body: %w", err)
}
texts := make([]string, 0)
images := make(map[string]string)
for _, line := range strings.Split(strings.TrimSpace(string(data)), "\n") {View on GitHub (pinned to 988cbb0330)
Solutions
- Inspect the URL in the error (%v wraps the SSRF validation reason) and confirm who produced it — a private IP from the public cloud provider signals compromise or misconfiguration.
- For self-hosted deployments, add the internal result host to the SSRF allowlist (utils.ValidateURLForSSRF allowlist configuration) instead of disabling the check.
- Ensure the provider returns public, HTTPS result URLs (check base-URL/endpoint configuration).
- Never disable the SSRF check to make the error go away on internet-facing deployments.
- In tests, point the SSRF allowlist at the local mock rather than disabling validation.
Example fix
// before
url, err := reader.Read(ctx, file)
// err: jsonl URL blocked by SSRF check: private address
// after: allowlist the self-hosted result host before calling
utils.AddSSRFAllowedHost("results.ocr.internal")
url, err := reader.Read(ctx, file)
if err != nil {
if strings.Contains(err.Error(), "SSRF") {
return fmt.Errorf("provider returned non-public result URL; refusing download: %w", err)
}
return err
} Defensive patterns
Strategy: validation
Validate before calling
// caller-side sanity check mirroring the library guard
u, err := url.Parse(resultURL)
if err != nil || (u.Scheme != "https" && u.Scheme != "http") {
return fmt.Errorf("suspicious result URL: %q", resultURL)
}
if utils.ValidateURLForSSRF(resultURL) != nil {
return fmt.Errorf("result URL is not publicly reachable; refusing download")
} Type guard
func isPublicHTTPResultURL(raw string) bool {
u, err := url.Parse(raw)
if err != nil || (u.Scheme != "https" && u.Scheme != "http") {
return false
}
return utils.ValidateURLForSSRF(raw) == nil
} Try / catch
if err := reader.Read(ctx, file); err != nil {
if strings.Contains(err.Error(), "SSRF") {
log.Warnf("provider returned blocked result URL: %v", err)
return ErrUntrustedResultURL
}
return err
} Prevention
- Never disable ValidateURLForSSRF on internet-facing deployments.
- For self-hosted deployments, use the SSRF allowlist for internal result hosts.
- Treat provider-supplied URLs as untrusted input everywhere, not just here.
- Alert when this error fires — it may indicate a compromised or misconfigured provider.
When it happens
Trigger: Read succeeds through pollJob, but the returned jsonl URL fails ValidateURLForSSRF — e.g. it resolves to 127.0.0.1, 10.x/172.16.x/192.168.x, 169.254.x, or uses a blocked scheme/port.
Common situations: Self-hosted PaddleOCR deployment behind an internal network where the genuine result URL is a private IP (SSRF guard is correct but blocks a legitimate internal host); DNS rebinding or a compromised/misconfigured provider returning internal URLs; a stub/mock server returning placeholder URLs like http://localhost/result.jsonl in tests.
Related errors
- unsafe MinIO endpoint: %w
- unsafe OSS endpoint: %w
- unsafe S3 endpoint: %w
- unsafe TOS endpoint: %w
- %s failed SSRF validation: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/d6705be6fe87d450.
Report an issue: GitHub.