crewAIInc/crewAI · error · ValueError
Path traversal not allowed: {self.path}
Error message
Path traversal not allowed: {self.path} What it means
Validation error from FilePath's model_validator: the string form of the supplied path contains '..' anywhere, which is treated as an attempted directory traversal and rejected outright. The check is substring-based on str(self.path), so even a legitimate filename like 'report..final.pdf' or a directory named 'a..b' trips it. This is a security guard for user-supplied paths (e.g. uploaded filenames), applied unconditionally.
Source
Thrown at lib/crewai-files/src/crewai_files/core/sources.py:225
"""File loaded from a filesystem path."""
path: Path = Field(description="Path to the file on the filesystem.")
max_size_bytes: int = Field(
default=DEFAULT_MAX_FILE_SIZE_BYTES,
exclude=True,
description="Maximum file size in bytes.",
)
_content: bytes | None = PrivateAttr(default=None)
_content_type: str = PrivateAttr()
@model_validator(mode="after")
def _validate_file_exists(self) -> FilePath:
"""Validate that the file exists, is secure, and within size limits."""
from crewai_files.processing.exceptions import FileTooLargeError
path_str = str(self.path)
if ".." in path_str:
raise ValueError(f"Path traversal not allowed: {self.path}")
if self.path.is_symlink():
resolved = self.path.resolve()
cwd = Path.cwd().resolve()
if not str(resolved).startswith(str(cwd)):
raise ValueError(f"Symlink escapes allowed directory: {self.path}")
if not self.path.exists():
raise ValueError(f"File not found: {self.path}")
if not self.path.is_file():
raise ValueError(f"Path is not a file: {self.path}")
actual_size = self.path.stat().st_size
if actual_size > self.max_size_bytes:
raise FileTooLargeError(
f"File exceeds max size ({actual_size} > {self.max_size_bytes})",
file_name=str(self.path),
actual_size=actual_size,View on GitHub (pinned to 754d7323be)
Solutions
- Strip or reject '..' in user input before constructing FilePath: sanitize filenames at the trust boundary.
- If '..' appears only inside a filename, rename the file (e.g. replace '..' with '__') before creating the source.
- Resolve and re-relativize paths yourself first so no '..' segments remain in the string.
Example fix
# before
name = "report..final.pdf"
src = FilePath(path=upload_dir / name) # ValueError
# after
safe_name = name.replace("..", "__")
src = FilePath(path=upload_dir / safe_name) Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def safe_path(raw: str) -> bool:
return ".." not in str(raw) Try / catch
try:
FilePath(path=p)
except ValidationError as e:
if "Path traversal" in str(e):
raise PermissionError(f"rejected user path {p}") from e Prevention
- Sanitize user-supplied filenames at ingestion: strip path separators and '..'.
- Use uuid-based or slugified storage names for uploads instead of raw user filenames.
- Note the check is substring-based — even '..' inside a filename trips it.
When it happens
Trigger: FilePath(path=Path("data/../../etc/passwd")), but also FilePath(path=Path("uploads/my..file.txt")) or any path where a component contains '..' as part of a name — the naive substring check cannot distinguish traversal from naming.
Common situations: Processing user-uploaded filenames that legitimately contain '..'; joining user input into paths where normalization would actually stay inside the root; tests using '..'-containing fixtures.
Related errors
- Invalid skill reference: org and name must be single, non-em
- Symlink escapes allowed directory: {self.path}
- Path '{format_path_for_display(resolved_path, resolved_base)
- Blocked path traversal attempt: {member.name!r}
- Blocked unsupported tar member: {member.name!r}
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/3609f78f5e477915.
Report an issue: GitHub.