{"record":{"id":"62407f5c787172a9","repo":"oobabooga/textgen","slug":"invalid-url-backslashes-are-not-allowed","errorCode":null,"errorMessage":"Invalid URL: backslashes are not allowed","messagePattern":"Invalid URL: backslashes are not allowed","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"modules/web_search.py","lineNumber":20,"sourceCode":"import ipaddress\nimport socket\nfrom concurrent.futures import as_completed\nfrom datetime import datetime\nfrom urllib.parse import urljoin, urlparse\n\nimport requests\nfrom ddgs import DDGS\n\nfrom modules import shared\nfrom modules.logging_colors import logger\n\n\ndef _validate_url(url):\n    \"\"\"Validate that a URL is safe to fetch (not targeting private/internal networks).\"\"\"\n    # Reject characters that cause parsing discrepancies between urlparse and requests,\n    # which can be exploited to bypass SSRF protections (GHSA-27xf-58m5-vxmc).\n    if '\\\\' in url:\n        raise ValueError(\"Invalid URL: backslashes are not allowed\")\n\n    parsed = urlparse(url)\n    if parsed.scheme not in ('http', 'https'):\n        raise ValueError(f\"Unsupported URL scheme: {parsed.scheme}\")\n\n    if '@' in parsed.netloc:\n        raise ValueError(\"Invalid URL: userinfo (credentials) in URLs is not allowed\")\n\n    hostname = parsed.hostname\n    if not hostname:\n        raise ValueError(\"No hostname in URL\")\n\n    # Resolve hostname and check all returned addresses\n    try:\n        for family, _, _, _, sockaddr in socket.getaddrinfo(hostname, None):\n            ip = ipaddress.ip_address(sockaddr[0])\n            if not ip.is_global:\n                raise ValueError(f\"Access to non-public address {ip} is blocked\")","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/oobabooga/textgen/blob/ed888c71f221df552750e1834b3654abab8ae345/modules/web_search.py#L2-L38","documentation":"Part of the SSRF guard in _validate_url(). A backslash in the URL is rejected outright because Python's urlparse and HTTP libraries can disagree about how they treat '\\' (some parsers treat it as a path separator like '/'), letting an attacker craft a URL that passes validation but is fetched against a different target (GHSA-27xf-58m5-vxmc). Any URL containing '\\' fails before scheme or host checks run.","triggerScenarios":"Calling web-search/page-download functions (safe_get, download_web_page, etc.) with a URL containing a literal backslash, e.g. copied from Windows-style text ('https://example.com\\path'), a mis-encoded redirect target, or a maliciously crafted redirect Location header containing backslashes.","commonSituations":"User pastes a URL copied from Windows docs or chat that uses backslashes; a search result or RSS feed contains malformed URLs; a redirect chain returns a Location value with unescaped backslashes; penetration testing / security scanning of the web-fetch endpoint.","solutions":["Sanitize the URL before fetching: replace backslashes with forward slashes if the intent is a path separator, or reject/percent-encode them.","If the URL comes from user input, validate/normalize it client-side before submitting to the search or web-fetch API.","If it comes from a redirect, this error is the guard working as intended — the target site is emitting malformed or hostile redirects; catch it and surface a friendly message.","Check for copy/paste artifacts like trailing '\\\\' or 'https:\\\\example.com' (double backslash after scheme) and fix to 'https://'."],"exampleFix":"# before\nresult = download_web_page('https:\\\\example.com\\\\page')  # raises ValueError\n\n# after\nurl = url.strip().replace('\\\\', '/')\nresult = download_web_page(url)","handlingStrategy":"validation","validationCode":"def is_fetchable_url(url: str) -> bool:\n    return isinstance(url, str) and '\\\\' not in url and url.startswith(('http://', 'https://'))\n\nurl = url.strip().replace('\\\\', '/')  # normalize accidental Windows-style slashes\nif not is_fetchable_url(url):\n    raise ValueError(f'Not a fetchable http(s) URL: {url!r}')","typeGuard":null,"tryCatchPattern":"try:\n    resp = safe_get(url)\nexcept ValueError as e:\n    if 'backslash' in str(e):\n        url = url.replace('\\\\', '/')\n        resp = safe_get(url)  # one normalized retry, then give up\n    else:\n        raise","preventionTips":["Normalize pasted URLs (strip, replace backslashes) before submitting to any web-fetch API.","Treat backslash URLs from redirects as hostile; never auto-retry them unmodified.","In UIs, run basic client-side URL validation before the request reaches the server."],"tags":["ssrf","url-validation","security","web-fetch"],"backgroundTag":null,"analyzedSha":"ed888c71f221df552750e1834b3654abab8ae345","analyzedAt":"2026-08-15T05:24:21.000Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}