crewAIInc/crewAI · error · ValueError
Blocked unsafe file path: {e}
Error message
Blocked unsafe file path: {e} What it means
Raised in RAGTool.add()'s per-argument loop when a value 'looks like a file path' (contains a path separator, starts with '.', or is absolute) and validate_file_path rejects it. On success the argument is rewritten to the resolved real path specifically to prevent symlink TOCTOU; on failure the guard's reason is wrapped as 'Blocked unsafe file path: <reason>'.
Source
Thrown at lib/crewai-tools/src/crewai_tools/tools/rag/rag_tool.py:331
validate_url(source_ref)
except ValueError as e:
raise ValueError(f"Blocked unsafe URL: {e}") from e
validated_args.append(arg)
continue
# Check if it looks like a file path (not a plain text string).
# Check both os.sep (backslash on Windows) and "/" so that
# forward-slash paths like "sub/file.txt" are caught on all platforms.
if (
os.path.sep in source_ref
or "/" in source_ref
or source_ref.startswith(".")
or os.path.isabs(source_ref)
):
try:
resolved_ref = validate_file_path(source_ref)
except ValueError as e:
raise ValueError(f"Blocked unsafe file path: {e}") from e
# Use the resolved path to prevent symlink TOCTOU
if isinstance(arg, dict):
arg = {**arg}
if "source" in arg:
arg["source"] = resolved_ref
elif "content" in arg:
arg["content"] = resolved_ref
else:
arg = resolved_ref
validated_args.append(arg)
# Validate keyword path/URL arguments — these are equally user-controlled
# and must not bypass the checks applied to positional args.
if "path" in kwargs and kwargs.get("path") is not None:
kwargs["path"] = _check_path(str(kwargs["path"]), "path")
if "file_path" in kwargs and kwargs.get("file_path") is not None:
kwargs["file_path"] = _check_path(str(kwargs["file_path"]), "file_path")View on GitHub (pinned to 754d7323be)
Solutions
- Pass only paths inside the configured allowed root
- Check the embedded validate_file_path reason (traversal / absolute / symlink escape) and fix accordingly
- If your text genuinely contains slashes and isn't a path, wrap it as {'content': text} so it isn't heuristically treated as a file
- Symlink legitimate data into the allowed root rather than pointing outside it
Example fix
# before
rag_tool.add('../shared/knowledge.pdf') # ValueError: Blocked unsafe file path
# after
rag_tool.add('knowledge/knowledge.pdf') # inside allowed root
# or for slash-containing TEXT:
rag_tool.add({'content': 'routes: /api/v1 /api/v2'})
Defensive patterns
Strategy: validation
Validate before calling
import os
from crewai_tools.security.safe_path import validate_file_path
def addable_path(p: str) -> bool:
if not (os.sep in p or "/" in p or p.startswith(".") or os.path.isabs(p)):
return True # plain text, not treated as path
try:
validate_file_path(p)
return True
except ValueError:
return False Type guard
def looks_like_path(s: str) -> bool:
return os.sep in s or "/" in s or s.startswith(".") or os.path.isabs(s) Try / catch
try:
rag_tool.add(item)
except ValueError as e:
if "Blocked unsafe file path" in str(e):
raise PermissionError(f"path outside allowed root: {item}") from e
raise Prevention
- Remember: any string containing '/' is heuristically path-checked — wrap slash-containing prose as {'content': text}
- Keep documents inside the allowed root; symlink them in rather than pointing outside
- Reject user inputs containing '..' before they reach add()
- Use the resolved path returned by the guard (it also defeats symlink TOCTOU)
When it happens
Trigger: rag_tool.add('/etc/shadow'), rag_tool.add('../../secrets/.env'), or any path that resolves outside the allowed root — including via symlinks. The path-detection heuristic also fires on any string containing '/', so 'some/relative/file.txt' is treated as a path, not plain text.
Common situations: Agents told to 'read all project files' reaching into .env/keys; symlinked data directories escaping the sandbox; users surprised that text containing slashes is path-validated; containerized runs where allowed roots are mounted differently.
Related errors
- Blocked unsafe {label}: {e}
- Blocked unsafe URL: {e}
- Invalid skill reference: org and name must be single, non-em
- Blocked path traversal attempt: {member.name!r}
- Blocked link target escaping destination: {member.name!r} ->
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/9d4abd2e5862cba1.
Report an issue: GitHub.