{"record":{"id":"e6b6c8e6ba91048c","repo":"BerriAI/litellm","slug":"invalid-file-path-file-path-r-contains-url-spec","errorCode":null,"errorMessage":"Invalid file path {file_path!r}: contains URL special characters","messagePattern":"Invalid file path (.+?): contains URL special characters","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"litellm/integrations/bitbucket/bitbucket_client.py","lineNumber":15,"sourceCode":"\"\"\"\nBitBucket API client for fetching .prompt files from BitBucket repositories.\n\"\"\"\n\nimport base64\nimport urllib.parse\nfrom typing import Any, Final\n\nfrom litellm.llms.custom_httpx.http_handler import HTTPHandler\n\n\ndef _sanitize_file_path(file_path: str) -> str:\n    \"\"\"Reject path traversal and URL-encode each path segment.\"\"\"\n    if \"#\" in file_path or \"?\" in file_path:\n        raise ValueError(f\"Invalid file path {file_path!r}: contains URL special characters\")\n    parts: Final = file_path.split(\"/\")\n    for part in parts:\n        if part == \"..\":\n            raise ValueError(f\"Invalid file path {file_path!r}: path traversal detected\")\n    return \"/\".join(urllib.parse.quote(part, safe=\"\") for part in parts)\n\n\nclass BitBucketClient:\n    \"\"\"\n    Client for interacting with BitBucket API to fetch .prompt files.\n\n    Supports:\n    - Authentication with access tokens\n    - Fetching file contents from repositories\n    - Team-based access control through BitBucket permissions\n    - Branch-specific file fetching\n    \"\"\"\n","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/integrations/bitbucket/bitbucket_client.py#L1-L33","documentation":"A deliberate security guard in _sanitize_file_path: before URL-encoding path segments for the BitBucket raw-file API, the function rejects any file path containing '#' or '?'. Those characters have special meaning in URLs and could otherwise alter the request target (e.g. truncate the path at a fragment or inject query params), so they are treated as invalid input rather than escaped.","triggerScenarios":"Calling get_file (directly or via the BitBucket prompt manager) with a file path containing '#' or '?', e.g. 'prompts/summarize#v2.prompt' or 'faq/q?a.prompt'; user-supplied prompt paths passed through without sanitization; prompt_id strings copied from URLs that include fragments.","commonSituations":"Prompt IDs derived from URLs or user input containing anchors/query strings; files genuinely named with '#' or '?' (must be renamed — the guard is unconditional); testing the integration with hand-crafted paths.","solutions":["Remove '#' and '?' from the file path / prompt_id used to address the file","Rename the repository file if it actually contains those characters","Sanitize external input before passing it as a path (strip fragments/queries at your API boundary)"],"exampleFix":"# before\ncontent = client.get_file(\"prompts/summarize#latest.prompt\")  # ValueError\n\n# after\ncontent = client.get_file(\"prompts/summarize-latest.prompt\")","handlingStrategy":"validation","validationCode":"def validate_file_path(file_path: str) -> str:\n    if \"#\" in file_path or \"?\" in file_path:\n        raise ValueError(f\"path must not contain '#' or '?': {file_path!r}\")\n    return file_path\n\npath = validate_file_path(user_supplied_path)\ncontent = client.get_file(path)","typeGuard":"def is_safe_prompt_path(p: str | None) -> bool:\n    if not isinstance(p, str) or not p:\n        return False\n    return \"#\" not in p and \"?\" not in p and \"..\" not in p.split(\"/\") and p.endswith(\".prompt\")","tryCatchPattern":"try:\n    client.get_file(path)\nexcept ValueError as e:\n    if \"URL special characters\" in str(e):\n        path = path.split(\"#\")[0].split(\"?\")[0]  # or reject input outright\n        raise ValueError(\"reject user paths containing fragments/queries\") from e\n    raise","preventionTips":["Strip URL fragments and query strings from any path derived from URLs or user input before passing to the client","Restrict prompt paths to an allow-listed directory prefix and .prompt extension","Never build API paths by concatenating raw user input"],"tags":["bitbucket","path-validation","security","url-encoding"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}