{"record":{"id":"9e3528b03f8b30bf","repo":"unslothai/unsloth","slug":"provider-base-url-contains-invalid-characters","errorCode":null,"errorMessage":"Provider base URL contains invalid characters.","messagePattern":"Provider base URL contains invalid characters\\.","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"studio/backend/core/inference/providers.py","lineNumber":874,"sourceCode":"\n    The backend issues outbound requests to this URL with the caller's decrypted\n    API key attached, so it is caller-controlled server-side egress. Only shapes\n    that can never be a real provider endpoint are refused: a non-http(s) scheme,\n    control characters, a missing host, and cloud metadata services. Plain http,\n    loopback, LAN hosts, odd ports, query strings and basic-auth userinfo all\n    stay valid -- Ollama, llama.cpp, vLLM and custom gateways rely on them. A\n    caller-supplied hostname is resolved far enough to apply the metadata block\n    to DNS aliases of it; rejecting other private addresses stays opt-in.\n\n    Normalization is strip + trailing-slash removal only (what the client did\n    before), so validating an already-validated URL returns it unchanged.\n    \"\"\"\n    if not isinstance(base_url, str) or not base_url.strip():\n        raise ValueError(\"Provider base URL is required.\")\n\n    raw = base_url.strip()\n    if any(char.isspace() or ord(char) < 32 or ord(char) == 127 for char in raw) or \"\\\\\" in raw:\n        raise ValueError(\"Provider base URL contains invalid characters.\")\n\n    try:\n        parts = urlsplit(raw)\n        port = parts.port\n        hostname = parts.hostname\n    except ValueError as exc:\n        raise ValueError(\"Provider base URL is malformed.\") from exc\n\n    scheme = parts.scheme.lower()\n    if scheme not in (\"http\", \"https\"):\n        raise ValueError(\"Provider base URL must use http or https.\")\n    # Userinfo stays allowed for gateways behind basic auth; the checks below read\n    # the parsed hostname, so http://api.openai.com@169.254.169.254/ is caught.\n    if not hostname:\n        raise ValueError(\"Provider base URL must contain a hostname.\")\n\n    hostname = hostname.rstrip(\".\")\n    if _metadata_host(hostname) or _resolves_to_metadata(hostname, port, scheme):","sourceCodeStart":856,"sourceCodeEnd":892,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/inference/providers.py#L856-L892","documentation":"Raised when the stripped base URL contains whitespace anywhere, control characters (codepoint < 32 or 127), or a backslash. These characters cannot appear in a legitimate endpoint URL and are classic injection/smuggling vectors for parser-differential attacks, so validation fails before urlsplit ever runs.","triggerScenarios":"A pasted URL containing a newline, tab, or trailing invisible character; a backslash-based path like http://host\\path; a URL copied from a PDF with soft line breaks embedded.","commonSituations":"Copy-paste from documents/slides introducing hidden characters; user typing a URL with an embedded space; crafted input attempting header or path confusion.","solutions":["Retype or carefully re-paste the URL, removing embedded spaces/line breaks.","Sanitize input at the form level: reject or strip control characters before submit.","Inspect the raw string with repr() to find the offending character."],"exampleFix":"# before\nvalidate_provider_base_url(\"https://api.example.com/v1\\n\")\n# after\nvalidate_provider_base_url(\"https://api.example.com/v1\")","handlingStrategy":"validation","validationCode":"def has_no_bad_chars(url: str) -> bool:\n    return not any(c.isspace() or ord(c) < 32 or ord(c) == 127 for c in url) and \"\\\\\" not in url","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Sanitize pasted URLs in the client (strip whitespace/control chars).","Inspect suspicious values with repr() to spot invisible characters."],"tags":["validation","injection","provider-config","input"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}