{"record":{"id":"0ce0b41c17854940","repo":"BerriAI/litellm","slug":"advisor-tool-definition-sets-api-base-but-the-pr","errorCode":null,"errorMessage":"advisor tool definition sets 'api_base' but the proxy has TLS verification disabled (litellm.ssl_verify=False), so a caller-supplied api_base can't be safely validated against DNS rebinding.","messagePattern":"advisor tool definition sets 'api_base' but the proxy has TLS verification disabled \\(litellm\\.ssl_verify=False\\), so a caller-supplied api_base can't be safely validated against DNS rebinding\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/anthropic/experimental_pass_through/messages/interceptors/advisor.py","lineNumber":223,"sourceCode":"    ``anthropic_messages()`` call chain.\n    \"\"\"\n    if not _allow_client_side_advisor_credentials():\n        return None, None\n    api_key: Final[str | None] = advisor_tool.get(\"api_key\")\n    api_base: Final[str | None] = advisor_tool.get(\"api_base\")\n    if api_base is None:\n        return api_key, None\n    if not api_key:\n        raise ValueError(\n            \"advisor tool definition sets 'api_base' without 'api_key'. A \"\n            \"caller-supplied api_base is only honored alongside a \"\n            \"caller-supplied api_key, so the proxy's own credentials are \"\n            \"never sent to a caller-chosen destination.\"\n        )\n    if not api_base.startswith(\"https://\"):\n        raise ValueError(f\"advisor tool definition sets 'api_base'={api_base!r}, which must use the https scheme.\")\n    if getattr(litellm, \"ssl_verify\", True) is False:\n        raise ValueError(\n            \"advisor tool definition sets 'api_base' but the proxy has TLS verification \"\n            \"disabled (litellm.ssl_verify=False), so a caller-supplied api_base can't be \"\n            \"safely validated against DNS rebinding.\"\n        )\n    if getattr(litellm, \"user_url_validation\", True):\n        validate_url(api_base)\n    return api_key, api_base\n\n\ndef _make_synthetic_advisor_tool() -> dict:\n    \"\"\"Build a regular tool definition the executor provider can understand.\"\"\"\n    return {\n        \"name\": \"advisor\",\n        \"description\": ADVISOR_TOOL_DESCRIPTION,\n        \"input_schema\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"question\": {","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/anthropic/experimental_pass_through/messages/interceptors/advisor.py#L205-L241","documentation":"Third guard in the advisor credential chain: a caller-supplied api_base is refused when litellm.ssl_verify is False. With TLS verification disabled, certificate validation cannot block DNS-rebinding attacks against the https-scheme check, so the resolver refuses the combination rather than ship an unsafe path. Note disabling ssl_verify globally also disables this feature.","triggerScenarios":"Advisor tool with api_base (https) and api_key, while the process runs with litellm.ssl_verify = False (commonly set to tolerate self-signed certificates in dev). getattr(litellm, 'ssl_verify', True) is False and the ValueError fires.","commonSituations":"Dev environments with self-signed certs where developers set litellm.ssl_verify=False as a workaround; CI pipelines that disable verification globally; the same flag set to work with other self-signed providers breaking advisor custom bases.","solutions":["Re-enable TLS verification (remove litellm.ssl_verify = False) and add the internal CA / self-signed cert to the trust store (e.g. via REQUESTS_CA_BUNDLE or SSL_CERT_FILE).","Or terminate TLS properly for the destination with a publicly trusted cert.","Or move the destination into server-side proxy config where credentials are gateway-owned, avoiding caller-supplied api_base entirely."],"exampleFix":"# before\nimport litellm\nlitellm.ssl_verify = False  # breaks caller-supplied advisor api_base\n\n# after\nimport os\nos.environ[\"REQUESTS_CA_BUNDLE\"] = \"/path/to/internal-ca.pem\"  # trust the internal CA instead","handlingStrategy":"validation","validationCode":"import litellm\n\ndef advisor_custom_base_allowed() -> bool:\n    return getattr(litellm, \"ssl_verify\", True) is not False","typeGuard":"def advisor_config_is_safe(advisor_tool: dict, ssl_verify: bool = True) -> bool:\n    api_base = advisor_tool.get(\"api_base\")\n    if api_base is None:\n        return True\n    return ssl_verify and api_base.startswith(\"https://\") and bool(advisor_tool.get(\"api_key\"))","tryCatchPattern":"try:\n    resp = litellm.anthropic_messages(tools=tools, ...)\nexcept ValueError as e:\n    if \"TLS verification disabled\" in str(e):\n        return http_error(400, \"caller-supplied api_base requires ssl_verify=True\")\n    raise","preventionTips":["Never run litellm.ssl_verify=False in production; trust internal CAs via REQUESTS_CA_BUNDLE instead.","Feature-detect: if ssl_verify is disabled, drop caller-supplied api_base support.","Alert on any deployment config combining ssl_verify=False with advisor custom bases."],"tags":["anthropic","advisor","security","ssl","dns-rebinding"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}