{"record":{"id":"011a71cbd6acf89b","repo":"FoundationAgents/OpenManus","slug":"path-contains-potentially-unsafe-patterns","errorCode":null,"errorMessage":"Path contains potentially unsafe patterns","messagePattern":"Path contains potentially unsafe patterns","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"app/sandbox/core/sandbox.py","lineNumber":246,"sourceCode":"\n        except Exception as e:\n            raise RuntimeError(f\"Failed to write file: {e}\")\n\n    def _safe_resolve_path(self, path: str) -> str:\n        \"\"\"Safely resolves container path, preventing path traversal.\n\n        Args:\n            path: Original path.\n\n        Returns:\n            Resolved absolute path.\n\n        Raises:\n            ValueError: If path contains potentially unsafe patterns.\n        \"\"\"\n        # Check for path traversal attempts\n        if \"..\" in path.split(\"/\"):\n            raise ValueError(\"Path contains potentially unsafe patterns\")\n\n        resolved = (\n            os.path.join(self.config.work_dir, path)\n            if not os.path.isabs(path)\n            else path\n        )\n        return resolved\n\n    async def copy_from(self, src_path: str, dst_path: str) -> None:\n        \"\"\"Copies a file from the container.\n\n        Args:\n            src_path: Source file path (container).\n            dst_path: Destination path (host).\n\n        Raises:\n            FileNotFoundError: If source file does not exist.\n            RuntimeError: If copy operation fails.","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/FoundationAgents/OpenManus/blob/52a13f2a57d8c7f6737eefb02ccf569594d44273/app/sandbox/core/sandbox.py#L228-L264","documentation":"Raised as ValueError by DockerSandbox._safe_resolve_path (app/sandbox/core/sandbox.py:246) when any single path segment equals '..' — a deliberate path-traversal block before the path is used with Docker APIs. It fires on the raw string segments, so even a benign-looking 'foo/../bar' is rejected; there is no allowlist.","triggerScenarios":"Passing a path containing '..' to read_file/write_file/copy_from/copy_to; LLM-generated tool arguments that include traversal; joining an unvalidated user string into a container path; normalizing paths with os.path.normpath on the caller side and still containing '..' segments that escape the root.","commonSituations":"Agent tool receives ' ../../etc/passwd' style inputs; caller pre-normalizes 'a/./b/../c' — normpath keeps '..' segments when they would climb above the base; Windows-style '..\\\\' does NOT match the split('/') check and may bypass it (defense depth note).","solutions":["Sanitize on the caller side: use os.path.basename for filenames, or normalize and re-verify the result stays under work_dir.","Strip/reject '..' segments (and ideally '..\\\\' too) before passing user-derived strings.","Use absolute paths already known to be under the work_dir volume.","For user uploads, generate server-side safe names (uuid + sanitized basename)."],"exampleFix":"# before\nawait sandbox.write_file(f\"uploads/{user_filename}\", data)  # user_filename may contain '..'\n\n# after\nsafe = os.path.basename(user_filename.replace(\"..\", \"_\")).strip() or \"upload.bin\"\nawait sandbox.write_file(f\"uploads/{safe}\", data)","handlingStrategy":"validation","validationCode":"def safe_container_path(path: str, work_dir: str) -> str:\n    parts = [p for p in path.replace(\"\\\\\", \"/\").split(\"/\") if p not in (\"\", \".\", \"..\")]\n    candidate = os.path.normpath(os.path.join(work_dir, *parts))\n    if not candidate.startswith(os.path.normpath(work_dir)):\n        raise ValueError(f\"escapes work_dir: {path!r}\")\n    return candidate","typeGuard":"def is_safe_path(path: str) -> bool:\n    return \"..\" not in path.replace(\"\\\\\", \"/\").split(\"/\")","tryCatchPattern":"try:\n    await sandbox.write_file(user_path, data)\nexcept ValueError as e:\n    if \"unsafe patterns\" in str(e):\n        user_path = os.path.basename(user_path)  # degrade to basename and retry once","preventionTips":["Never pass unvalidated user/LLM strings as container paths","Prefer basenames under a fixed uploads dir","Normalize with normpath then re-verify containment under work_dir","Reject backslash traversal too — the built-in check only splits on '/'"],"tags":["sandbox","path-traversal","security","validation","value-error"],"backgroundTag":null,"analyzedSha":"52a13f2a57d8c7f6737eefb02ccf569594d44273","analyzedAt":"2026-08-15T02:33:49.993Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}