{"record":{"id":"d2b82a76429b0732","repo":"invoke-ai/InvokeAI","slug":"parent-directory-references-not-allowed-in-subfold","errorCode":null,"errorMessage":"Parent directory references not allowed in subfolder path","messagePattern":"Parent directory references not allowed in subfolder path","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"invokeai/app/services/image_files/image_files_disk.py","lineNumber":289,"sourceCode":"\n        if not resolved_image_path.is_relative_to(resolved_base):\n            raise ValueError(\"Image path outside outputs folder, potential directory traversal detected\")\n\n        return resolved_image_path\n\n    @staticmethod\n    def _validate_subfolder(subfolder: str) -> None:\n        \"\"\"Validates a subfolder path to prevent directory traversal while allowing controlled subdirectories.\"\"\"\n        if not subfolder:\n            return\n        if \"\\\\\" in subfolder:\n            raise ValueError(\"Backslashes not allowed in subfolder path\")\n        if subfolder.startswith(\"/\"):\n            raise ValueError(\"Absolute paths not allowed in subfolder path\")\n        parts = subfolder.split(\"/\")\n        for part in parts:\n            if part == \"..\":\n                raise ValueError(\"Parent directory references not allowed in subfolder path\")\n            if part == \"\":\n                raise ValueError(\"Empty path segments not allowed in subfolder path\")\n\n    def validate_path(self, path: Union[str, Path]) -> bool:\n        \"\"\"Validates the path given for an image or thumbnail.\"\"\"\n        path = path if isinstance(path, Path) else Path(path)\n        return path.exists()\n\n    def get_workflow(self, image_name: str, image_subfolder: str = \"\") -> str | None:\n        image = self.get(image_name, image_subfolder=image_subfolder)\n        workflow = image.info.get(\"invokeai_workflow\", None)\n        if isinstance(workflow, str):\n            return workflow\n        return None\n\n    def get_graph(self, image_name: str, image_subfolder: str = \"\") -> str | None:\n        image = self.get(image_name, image_subfolder=image_subfolder)\n        graph = image.info.get(\"invokeai_graph\", None)","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/image_files/image_files_disk.py#L271-L307","documentation":"Any '/'-separated component equal to '..' in the subfolder is rejected because it references a parent directory, enabling classic directory traversal out of the outputs folder. Raises ValueError with the parent-directory message.","triggerScenarios":"Passing image_subfolder like '../secrets', 'a/../b', or '../../etc' to get/save/get_path.","commonSituations":"User-controlled board names containing '..'; hand-built relative paths; API requests crafted to escape the outputs directory (security probing).","solutions":["Remove or resolve '..' components from the subfolder before calling","Use a fixed set of allowed subfolder names (allowlist) rather than free-form paths","Normalize with PurePosixPath and reject if any part == '..'"],"exampleFix":"// before\nsub = f'{user_board}/../images'\n// after\nsub = posixpath.normpath(user_board)\nassert '..' not in PurePosixPath(sub).parts","handlingStrategy":"validation","validationCode":"from pathlib import PurePosixPath\ndef subfolder_is_safe(s: str) -> bool:\n    parts = PurePosixPath(s).parts\n    return bool(parts) and all(p not in ('..', '.', '') for p in parts) and '\\\\' not in s\nassert subfolder_is_safe('2024/08')","typeGuard":"def has_no_parent_refs(s: object) -> bool:\n    return isinstance(s, str) and '..' not in PurePosixPath(s).parts","tryCatchPattern":"try:\n    service.save(data, name, image_subfolder=subfolder)\nexcept ValueError as e:\n    if 'Parent directory' in str(e):\n        raise HTTPException(400, 'Subfolder may not reference parent directories') from e","preventionTips":["Never build subfolders from unvalidated user input","Allowlist known-good subfolder names instead of free-form paths","Run security tests covering '../' payloads against storage APIs"],"tags":["security","path-traversal","validation"],"backgroundTag":"directory-traversal","analyzedSha":"0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06","analyzedAt":"2026-08-29T04:46:49.967Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}