{"record":{"id":"3609f78f5e477915","repo":"crewAIInc/crewAI","slug":"path-traversal-not-allowed-self-path","errorCode":null,"errorMessage":"Path traversal not allowed: {self.path}","messagePattern":"Path traversal not allowed: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/crewai-files/src/crewai_files/core/sources.py","lineNumber":225,"sourceCode":"    \"\"\"File loaded from a filesystem path.\"\"\"\n\n    path: Path = Field(description=\"Path to the file on the filesystem.\")\n    max_size_bytes: int = Field(\n        default=DEFAULT_MAX_FILE_SIZE_BYTES,\n        exclude=True,\n        description=\"Maximum file size in bytes.\",\n    )\n    _content: bytes | None = PrivateAttr(default=None)\n    _content_type: str = PrivateAttr()\n\n    @model_validator(mode=\"after\")\n    def _validate_file_exists(self) -> FilePath:\n        \"\"\"Validate that the file exists, is secure, and within size limits.\"\"\"\n        from crewai_files.processing.exceptions import FileTooLargeError\n\n        path_str = str(self.path)\n        if \"..\" in path_str:\n            raise ValueError(f\"Path traversal not allowed: {self.path}\")\n\n        if self.path.is_symlink():\n            resolved = self.path.resolve()\n            cwd = Path.cwd().resolve()\n            if not str(resolved).startswith(str(cwd)):\n                raise ValueError(f\"Symlink escapes allowed directory: {self.path}\")\n\n        if not self.path.exists():\n            raise ValueError(f\"File not found: {self.path}\")\n        if not self.path.is_file():\n            raise ValueError(f\"Path is not a file: {self.path}\")\n\n        actual_size = self.path.stat().st_size\n        if actual_size > self.max_size_bytes:\n            raise FileTooLargeError(\n                f\"File exceeds max size ({actual_size} > {self.max_size_bytes})\",\n                file_name=str(self.path),\n                actual_size=actual_size,","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-files/src/crewai_files/core/sources.py#L207-L243","documentation":"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.","triggerScenarios":"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.","commonSituations":"Processing user-uploaded filenames that legitimately contain '..'; joining user input into paths where normalization would actually stay inside the root; tests using '..'-containing fixtures.","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."],"exampleFix":"# before\nname = \"report..final.pdf\"\nsrc = FilePath(path=upload_dir / name)  # ValueError\n\n# after\nsafe_name = name.replace(\"..\", \"__\")\nsrc = FilePath(path=upload_dir / safe_name)","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef safe_path(raw: str) -> bool:\n    return \"..\" not in str(raw)","typeGuard":null,"tryCatchPattern":"try:\n    FilePath(path=p)\nexcept ValidationError as e:\n    if \"Path traversal\" in str(e):\n        raise PermissionError(f\"rejected user path {p}\") from e","preventionTips":["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."],"tags":["security","path-traversal","validation","file-sources"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}