{"record":{"id":"b321e4fbbf720916","repo":"langchain-ai/deepagents","slug":"path-traversal-not-allowed","errorCode":null,"errorMessage":"Path traversal not allowed","messagePattern":"Path traversal not allowed","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"libs/deepagents/deepagents/backends/filesystem.py","lineNumber":207,"sourceCode":"        When `virtual_mode=False`, preserve legacy behavior: absolute paths are allowed\n        as-is; relative paths resolve under cwd.\n\n        Args:\n            key: File path (absolute, relative, or virtual when `virtual_mode=True`).\n\n        Returns:\n            Resolved absolute `Path` object.\n\n        Raises:\n            ValueError: If path traversal is attempted in `virtual_mode` or if the\n                resolved path escapes the root directory.\n            OSError: If the path is a symlink loop (`ELOOP`).\n        \"\"\"\n        if self.virtual_mode:\n            vpath = key if key.startswith(\"/\") else \"/\" + key\n            if \"..\" in vpath or vpath.startswith(\"~\"):\n                msg = \"Path traversal not allowed\"\n                raise ValueError(msg)\n            full = (self.cwd / vpath.lstrip(\"/\")).resolve()\n            try:\n                full.relative_to(self.cwd)\n            except ValueError:\n                msg = f\"Path:{full} outside root directory: {self.cwd}\"\n                raise ValueError(msg) from None\n            _raise_if_symlink_loop(full)\n            return full\n\n        path = Path(key)\n        if path.is_absolute():\n            _raise_if_symlink_loop(path)\n            return path\n        resolved = (self.cwd / path).resolve()\n        _raise_if_symlink_loop(resolved)\n        return resolved\n\n    def _to_virtual_path(self, path: Path) -> str:","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/deepagents/deepagents/backends/filesystem.py#L189-L225","documentation":"In virtual mode, FilesystemBackend resolves every key against its root directory and rejects paths that escape it. Any path containing a '..' segment or starting with '~' is refused up front with ValueError to keep the backend sandboxed to its root.","triggerScenarios":"Calling ls, read, write, edit, delete, or grep with a key like '../secrets.txt', 'a/../../etc/passwd', or '~/config' while the backend is in virtual_mode.","commonSituations":"LLM-generated paths containing '..', joining user input with a relative base, or shell-style '~/file' expansion habits applied to backend keys.","solutions":["Remove '..' segments and resolve to a path relative to the backend root before calling","Expand '~' yourself and pass the resulting path rooted inside the backend directory","Normalize the path (os.path.normpath / Path.resolve) and verify it stays under the intended root","If you truly need access outside the root, reconfigure the backend root_dir instead of traversing"],"exampleFix":"// before\nbackend.read(\"../settings.json\")\n// after\nbackend.read(\"settings.json\")  # relative to backend root","handlingStrategy":"validation","validationCode":"from pathlib import PurePosixPath\ndef is_safe_key(key: str) -> bool:\n    p = PurePosixPath(key.lstrip(\"/\"))\n    return \"..\" not in p.parts and not key.startswith(\"~\")\nassert is_safe_key(user_path), \"refusing traversal path\"","typeGuard":"def safe_backend_key(key: str) -> str | None:\n    parts = PurePosixPath(key.lstrip(\"/\")).parts\n    return key if \"..\" not in parts and not key.startswith(\"~\") else None","tryCatchPattern":"try:\n    content = backend.read(key)\nexcept ValueError as exc:\n    if \"Path traversal not allowed\" in str(exc):\n        content = None  # or re-resolve the key against the root\n    else:\n        raise","preventionTips":["Never forward raw LLM/user-supplied paths directly to backend calls","Normalize keys with PurePosixPath and drop '..' segments first","Keep all file references relative to the backend root"],"tags":["python","path-traversal","security","filesystem"],"backgroundTag":"path-traversal-blocked","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}