{"record":{"id":"a2b12718339f8fbe","repo":"invoke-ai/InvokeAI","slug":"invalid-image-name-potential-directory-traversal","errorCode":null,"errorMessage":"Invalid image name, potential directory traversal detected","messagePattern":"Invalid image name, potential directory traversal detected","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"invokeai/app/services/image_files/image_files_disk.py","lineNumber":259,"sourceCode":"        if not isinstance(token, _StagedDelete):\n            raise ImageFileDeleteException(\"Invalid staged-delete token\")\n        try:\n            for source, destination in reversed(token.files):\n                if destination.exists():\n                    source.parent.mkdir(parents=True, exist_ok=True)\n                    destination.replace(source)\n            shutil.rmtree(token.directory, ignore_errors=True)\n        except Exception as e:\n            raise ImageFileDeleteException from e\n\n    def get_path(self, image_name: str, thumbnail: bool = False, image_subfolder: str = \"\") -> Path:\n        base_folder = self.__thumbnails_folder if thumbnail else self.__output_folder\n        filename = get_thumbnail_name(image_name) if thumbnail else image_name\n\n        # Validate the filename itself (no path separators allowed in the filename)\n        basename = Path(filename).name\n        if basename != filename:\n            raise ValueError(\"Invalid image name, potential directory traversal detected\")\n\n        # Build the full path with optional subfolder\n        if image_subfolder:\n            self._validate_subfolder(image_subfolder)\n            image_path = base_folder / image_subfolder / basename\n        else:\n            image_path = base_folder / basename\n\n        # Ensure the image path is within the base folder to prevent directory traversal\n        resolved_base = base_folder.resolve()\n        resolved_image_path = image_path.resolve()\n\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","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/invoke-ai/InvokeAI/blob/0b6a024f2ff6a86bfb953dcdb9cc504ef7397a06/invokeai/app/services/image_files/image_files_disk.py#L241-L277","documentation":"ImageFileService.get_path validates that the image filename contains no path separators by comparing Path(filename).name to the original string. If they differ, the name embeds a directory component or traversal, so it raises this ValueError to prevent writing or reading outside the outputs folder.","triggerScenarios":"Calling get/save/stage_delete with an image_name containing '/' or backslashes (e.g. '../foo.png' or 'sub/dir.png'), or a thumbnail name derived from such a name.","commonSituations":"Passing user-supplied or API-derived image names that include relative paths; storing images with names built by joining folder+file instead of using the image_subfolder parameter; older code predating the subfolder feature.","solutions":["Strip any directory components from the name before calling, or pass the directory via the image_subfolder parameter instead","Sanitize the name with Path(name).name and verify it matches the input","Reject the input at your API boundary with an allowlist regex (e.g. ^[A-Za-z0-9._-]+$)"],"exampleFix":"// before\nservice.save(Path('uploads/img.png').read_bytes(), 'subdir/img.png')\n// after\nservice.save(Path('uploads/img.png').read_bytes(), 'img.png', image_subfolder='subdir')","handlingStrategy":"validation","validationCode":"from pathlib import PurePosixPath\nimport re\nNAME_RE = re.compile(r'^[A-Za-z0-9][A-Za-z0-9._-]*$')\ndef is_safe_image_name(name: str) -> bool:\n    return bool(NAME_RE.match(name)) and PurePosixPath(name).name == name\nif not is_safe_image_name(image_name): raise ValueError('bad image name')","typeGuard":"def is_safe_image_name(name: object) -> bool:\n    return isinstance(name, str) and '/' not in name and '\\\\' not in name and name not in ('', '.', '..')","tryCatchPattern":"try:\n    path = service.get_path(image_name, thumbnail=False)\nexcept ValueError as e:\n    logger.warning('Rejected image name %r: %s', image_name, e)\n    raise HTTPException(400, 'Invalid image name') from e","preventionTips":["Never concatenate directories into the image name; use image_subfolder","Validate names with a strict allowlist regex at the API boundary","Treat image names as opaque IDs, not filesystem paths"],"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"}