diff --git a/py/api/images.py b/py/api/images.py index bde28c1..3335773 100644 --- a/py/api/images.py +++ b/py/api/images.py @@ -1049,15 +1049,12 @@ class ImageRoutesMixin: } ) - # Verify this is actually our thumbnails directory + # Verify this is actually our thumbnails directory: a real child + # of the output root (symlinks resolved), not merely a path that + # shares its prefix such as "2/thumbnails". try: - thumbnails_dir_resolved = thumbnails_dir.resolve() - output_path_resolved = output_path.resolve() - if ( - not str(thumbnails_dir_resolved).startswith( - str(output_path_resolved) - ) + not _is_within(thumbnails_dir, output_path) or thumbnails_dir.name != "thumbnails" ): self.logger.error( diff --git a/tests/test_api_images.py b/tests/test_api_images.py index db0d598..7f879ea 100644 --- a/tests/test_api_images.py +++ b/tests/test_api_images.py @@ -1254,6 +1254,22 @@ class TestClearThumbnails(ImageRouteCoverageCase): status, _ = await self._json("POST", self.URL) self.assertEqual(status, 500) + async def test_sibling_prefix_directory_is_refused(self): + # "/out2/thumbnails" starts with "/out" as a string but is + # not inside it; a symlinked thumbnails dir pointing there must be + # refused rather than emptied. + out = self.comfy_dir / "out" + out.mkdir() + sibling = make_png(self.comfy_dir / "out2" / "thumbnails" / "a_thumb.png") + self._make_symlink(sibling.parent, out / "thumbnails") + self.api._find_comfyui_output_dir = lambda: str(out) + + status, data = await self._json("POST", self.URL) + + self.assertEqual(status, 400) + self.assertFalse(data["success"]) + self.assertTrue(sibling.is_file()) + class TestImagePromptLookup(ImageRouteCoverageCase):