{"record":{"id":"619a654c1bf0b898","repo":"BerriAI/litellm","slug":"path-parameter-param-name-cannot-include-o","errorCode":null,"errorMessage":"Path parameter '{param_name}' cannot include '.' or '..' segments","messagePattern":"Path parameter '(.+?)' cannot include '\\.' or '\\.\\.' segments","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/proxy/_experimental/mcp_server/openapi_to_mcp_generator.py","lineNumber":124,"sourceCode":"    \"_request_resolved_auth_headers\", default=None\n)\n\n\ndef _sanitize_path_parameter_value(param_value: object, param_name: str) -> str:\n    \"\"\"Ensure path params cannot introduce directory traversal.\"\"\"\n    if param_value is None:\n        return \"\"\n\n    value_str: Final = str(param_value)\n    if value_str == \"\":\n        return \"\"\n\n    normalized_value: Final = value_str.replace(\"\\\\\", \"/\")\n    if \"/\" in normalized_value:\n        raise ValueError(f\"Path parameter '{param_name}' must not contain path separators\")\n\n    if any(part in {\".\", \"..\"} for part in PurePosixPath(normalized_value).parts):\n        raise ValueError(f\"Path parameter '{param_name}' cannot include '.' or '..' segments\")\n\n    return quote(value_str, safe=\"\")\n\n\ndef load_openapi_spec(filepath: str) -> dict[str, Any]:\n    \"\"\"\n    Sync wrapper. For URL specs, use the shared/custom MCP httpx client.\n    \"\"\"\n    try:\n        # If we're already inside an event loop, prefer the async function.\n        asyncio.get_running_loop()\n        raise RuntimeError(\n            \"load_openapi_spec() was called from within a running event loop. \"\n            \"Use 'await load_openapi_spec_async(...)' instead.\"\n        )\n    except RuntimeError as e:\n        # \"no running event loop\" is fine; other RuntimeErrors we re-raise\n        if \"no running event loop\" not in str(e).lower():","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/_experimental/mcp_server/openapi_to_mcp_generator.py#L106-L142","documentation":"Second guard in _sanitize_path_parameter_value in the OpenAPI-to-MCP generator: after the slash check, the value is parsed with PurePosixPath and any '.' or '..' segment raises this ValueError, preventing dot-segment traversal (e.g. a value of '..' escaping one path level). Because any '/' already raised the earlier error, this branch in practice fires for a parameter whose entire value is '..' (or a lone '.' in callers that pre-split segments). Like the sibling error it is returned as \"Invalid path parameter: ...\" on the generated tool path.","triggerScenarios":"Calling a generated MCP tool with a path parameter value of exactly \"..\" (or \".\") for a path like /files/{parent}/items/{name}; commonly happens when a caller computes the parent segment with os.path and accidentally passes the '..' produced by a relative path.","commonSituations":"Defaulted/empty-optional arguments that fall back to '..'; path manipulation code (os.path.join, pathlib) leaking dot segments into tool args; test fixtures that use '..' as a sentinel ID.","solutions":["Pass a concrete segment value, never a dot-relative path component.","If the value comes from filesystem logic, resolve it (Path(x).resolve().name) or validate it before sending it to the tool.","Treat this error text in a tool result as untrusted-input feedback: reject the caller's input in your own app with a 4xx rather than retrying."],"exampleFix":"# before\nparent = os.path.join(base, \"..\")  # leaks '..'\nawait call_mcp_tool(server_id=\"fs\", tool_name=\"list_dir\", arguments={\"path\": parent})\n\n# after\nparent = os.path.basename(os.path.normpath(os.path.join(base, \"..\")))\nawait call_mcp_tool(server_id=\"fs\", tool_name=\"list_dir\", arguments={\"path\": parent})","handlingStrategy":"validation","validationCode":"def has_no_dot_segments(value: object) -> bool:\n    s = \"\" if value is None else str(value)\n    if \"/\" in s or \"\\\\\" in s:\n        return False\n    return s not in (\".\", \"..\")\n\nassert has_no_dot_segments(args[name]), f\"{name} must be a concrete segment\"","typeGuard":"from typing import TypeGuard\n\ndef is_safe_path_segment(value: object) -> TypeGuard[str]:\n    if not isinstance(value, str) or not value:\n        return False\n    return \"/\" not in value and \"\\\\\" not in value and value not in (\".\", \"..\")","tryCatchPattern":"try:\n    safe = _sanitize_path_parameter_value(value, name)\nexcept ValueError as e:\n    raise BadRequest(str(e)) from None\n# REST callers: a result string \"Invalid path parameter: Path parameter 'x' cannot include '.' or '..' segments\" is a permanent 4xx","preventionTips":["Never feed os.path/pathlib intermediates ('..', '.') into tool arguments; resolve them first.","Reject dot-segment values in your API layer with your own 400 before they reach the proxy.","Add unit tests for path-typed tool args covering '..', '.', and backslash variants."],"tags":["mcp","openapi","path-traversal","input-validation"],"backgroundTag":"path-traversal-blocked","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-24T22:17:12.610Z"}