{"record":{"id":"82363ae8643044bc","repo":"crewAIInc/crewAI","slug":"blocked-unsafe-url-e","errorCode":null,"errorMessage":"Blocked unsafe URL: {e}","messagePattern":"Blocked unsafe URL: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/crewai-tools/src/crewai_tools/tools/rag/rag_tool.py","lineNumber":315,"sourceCode":"        for arg in args:\n            source_ref = (\n                str(arg.get(\"source\", arg.get(\"content\", \"\")))\n                if isinstance(arg, dict)\n                else str(arg)\n            )\n\n            # Check if it's a URL — only catch urlparse-specific errors here;\n            # validate_url's ValueError must propagate so it is never silently bypassed.\n            try:\n                parsed = urlparse(source_ref)\n            except (ValueError, AttributeError):\n                parsed = None\n\n            if parsed is not None and parsed.scheme in (\"http\", \"https\", \"file\"):\n                try:\n                    validate_url(source_ref)\n                except ValueError as e:\n                    raise ValueError(f\"Blocked unsafe URL: {e}\") from e\n                validated_args.append(arg)\n                continue\n\n            # Check if it looks like a file path (not a plain text string).\n            # Check both os.sep (backslash on Windows) and \"/\" so that\n            # forward-slash paths like \"sub/file.txt\" are caught on all platforms.\n            if (\n                os.path.sep in source_ref\n                or \"/\" in source_ref\n                or source_ref.startswith(\".\")\n                or os.path.isabs(source_ref)\n            ):\n                try:\n                    resolved_ref = validate_file_path(source_ref)\n                except ValueError as e:\n                    raise ValueError(f\"Blocked unsafe file path: {e}\") from e\n                # Use the resolved path to prevent symlink TOCTOU\n                if isinstance(arg, dict):","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-tools/src/crewai_tools/tools/rag/rag_tool.py#L297-L333","documentation":"Raised in RAGTool.add()'s per-argument loop when a value parses as a URL (urlparse yields a scheme of http, https, or file) and validate_url rejects it. Only urlparse-specific parse errors are caught silently; the guard's own ValueError always propagates, wrapped as 'Blocked unsafe URL: <reason>', so a security rejection can never be silently bypassed.","triggerScenarios":"rag_tool.add('http://127.0.0.1:8080/health') or file:// URLs pointing at local files — anything whose scheme marks it a URL and whose host/scheme the SSRF guard blocks (loopback, private IP, metadata endpoints, file scheme).","commonSituations":"Trying to ingest file:// URLs for local documents (blocked — use a filesystem path instead); agents probing internal HTTP services during research tasks; localhost dev URLs in examples that work in docs but are blocked by the guard.","solutions":["For local files, pass the filesystem path ('./docs/x.pdf') instead of a file:// URL — the path branch validates it separately","For blocked http(s) hosts, fetch the content from an allowed context and add it as text content","Read the embedded validate_url reason to see the exact rule tripped","Keep agent-facing prompts away from internal hostnames to avoid repeated guard hits"],"exampleFix":"# before\nrag_tool.add('file:///home/user/report.pdf')  # ValueError: Blocked unsafe URL\n\n# after\nrag_tool.add('/home/user/report.pdf')  # handled by path validation, PDF auto-detected\n","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\nfrom crewai_tools.security.safe_path import validate_url\n\ndef addable_url(u: str) -> bool:\n    try:\n        parsed = urlparse(u)\n    except ValueError:\n        return False\n    if parsed.scheme in (\"http\", \"https\", \"file\"):\n        try:\n            validate_url(u)\n            return True\n        except ValueError:\n            return False\n    return False","typeGuard":null,"tryCatchPattern":"try:\n    rag_tool.add(source_ref)\nexcept ValueError as e:\n    if \"Blocked unsafe URL\" in str(e):\n        # local file? switch to a filesystem path so the path branch handles it\n        if source_ref.startswith(\"file://\"):\n            rag_tool.add(source_ref[len(\"file://\"):])\n        else:\n            raise\n    else:\n        raise","preventionTips":["Use filesystem paths, not file:// URLs, for local documents","Pre-check http(s) URLs with validate_url to get the rejection reason early","Keep agent prompts scoped to public web URLs","Log blocked URLs to spot agents probing internal endpoints"],"tags":["security","ssrf","url-validation","rag","guard"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}