BerriAI/litellm · error · SSRFError
Origin mismatch on scheme
Error message
Origin mismatch on scheme
What it means
Raised during litellm's SSRF-protected fetch when a redirect Location resolves to a URL whose scheme differs from the original request's scheme (e.g. https -> http or http -> https across a hop). Redirect validation enforces same-origin across scheme, host, and port for every hop, so a scheme downgrade/upgrade via redirect is rejected. The message omits the specific schemes to avoid leaking details to a potentially hostile caller.
Source
Thrown at litellm/litellm_core_utils/url_utils.py:349
Hostnames are compared case-insensitively. Default ports are made
explicit (HTTP→80, HTTPS→443) so ``https://api.example.com:443/...``
and ``https://api.example.com/...`` are treated as the same origin.
Error messages identify *which* component mismatched but never echo
the operator's ``expected`` host or the candidate's hostname back to
the caller — in the SSRF threat model the caller is the attacker,
and reflecting host info would be a secondary leak of operator
infrastructure details.
"""
candidate: Final = urlparse(candidate_url)
expected: Final = urlparse(expected_url)
if candidate.scheme not in _ALLOWED_SCHEMES:
raise SSRFError("URL scheme is not allowed")
if candidate.scheme != expected.scheme:
raise SSRFError("Origin mismatch on scheme")
candidate_host: Final = _normalize_host(candidate.hostname or "")
expected_host: Final = _normalize_host(expected.hostname or "")
if not candidate_host or candidate_host != expected_host:
raise SSRFError("Origin mismatch on host")
default_port: Final = 443 if candidate.scheme == "https" else 80
candidate_port: Final = candidate.port if candidate.port is not None else default_port
expected_port: Final = expected.port if expected.port is not None else default_port
if candidate_port != expected_port:
raise SSRFError("Origin mismatch on port")
_MAX_REDIRECTS: Final = 10
def _extract_redirect_url(response: Any, request_url: str) -> str:
"""Extract and resolve the redirect target from a response's Location header."""View on GitHub (pinned to 6c2dcb801b)
Solutions
- Use the final scheme directly: call safe_get with the https:// (or correct) form of the URL so no cross-scheme redirect hop occurs.
- Fix the origin server/proxy to not redirect across schemes for this resource.
- If a legitimate CDN hop is required, it must preserve scheme, host, and port — otherwise it will always be rejected.
Example fix
# before resp = safe_get(client, "http://api.example.com/files/1") # 301 -> https://... # after resp = safe_get(client, "https://api.example.com/files/1")
Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlparse
def canonicalize(url: str) -> str:
p = urlparse(url)
if p.scheme == "http" and p.port == 80:
return url # already canonical enough
return url
# Prefer calling safe_get with the https:// form up front to avoid scheme redirects Try / catch
from litellm.litellm_core_utils.url_utils import SSRFError
try:
resp = safe_get(client, url)
except SSRFError as e:
if "Origin mismatch on scheme" in str(e):
return bad_request("redirect changes scheme; use the https URL directly")
raise Prevention
- Always request the final scheme (usually https) directly.
- Configure your servers to never redirect across schemes.
- Catch origin-mismatch errors and surface a clear 400 instead of a 500.
When it happens
Trigger: safe_get('https://api.example.com/x') where the server responds 301/302 with Location: http://api.example.com/x (scheme downgrade), or the reverse — any hop where candidate.scheme != expected.scheme in _validate_same_origin.
Common situations: Servers that force HTTP->HTTPS or HTTPS->HTTP redirects; misconfigured reverse proxies adding a redirect loop across schemes; mixed-content style redirect setups; some CDNs redirecting to a different-scheme edge URL.
Related errors
- URL scheme is not allowed
- Origin mismatch on host
- Origin mismatch on port
- URL scheme '{parsed.scheme}' is not allowed
- MAVVRIK_API_ENDPOINT host must be a Mavvrik domain (e.g. htt
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/13b5cfc4a657ecf5.
Report an issue: GitHub.