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

  1. Strip or reject '..' in user input before constructing FilePath: sanitize filenames at the trust boundary.
  2. If '..' appears only inside a filename, rename the file (e.g. replace '..' with '__') before creating the source.
  3. 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

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


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/3609f78f5e477915. Report an issue: GitHub.