From f4fa394e0f03b013f1068c96cff168ad10bd0410 Mon Sep 17 00:00:00 2001 From: "Dr.Lt.Data" Date: Thu, 8 Jan 2026 18:22:29 +0900 Subject: [PATCH] fix(security): add input sanitization and path traversal protection - Sanitize config string values to prevent CRLF injection attacks - Add get_safe_snapshot_path() helper to validate snapshot targets - Block path traversal attempts in remove_snapshot and restore_snapshot endpoints - Reject targets containing /, \, .., or null characters --- glob/manager_core.py | 7 ++++++- glob/manager_server.py | 21 +++++++++++++++++++-- pyproject.toml | 2 +- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/glob/manager_core.py b/glob/manager_core.py index 48175ef6..e0b3a6fe 100644 --- a/glob/manager_core.py +++ b/glob/manager_core.py @@ -44,7 +44,7 @@ import manager_migration from node_package import InstalledNodePackage -version_code = [3, 39, 1] +version_code = [3, 39, 2] version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '') @@ -1701,6 +1701,11 @@ def write_config(): 'db_mode': get_config()['db_mode'], } + # Sanitize all string values to prevent CRLF injection attacks + for key, value in config['default'].items(): + if isinstance(value, str): + config['default'][key] = value.replace('\r', '').replace('\n', '').replace('\x00', '') + directory = os.path.dirname(manager_config_path) if not os.path.exists(directory): os.makedirs(directory) diff --git a/glob/manager_server.py b/glob/manager_server.py index b9391016..eff7c032 100644 --- a/glob/manager_server.py +++ b/glob/manager_server.py @@ -997,6 +997,15 @@ async def get_snapshot_list(request): return web.json_response({'items': items}, content_type='application/json') +def get_safe_snapshot_path(target): + """ + Safely construct a snapshot file path, preventing path traversal attacks. + """ + if '/' in target or '\\' in target or '..' in target or '\x00' in target: + return None + return os.path.join(core.manager_snapshot_path, f"{target}.json") + + @routes.get("/snapshot/remove") async def remove_snapshot(request): if not is_allowed_security_level('middle'): @@ -1005,8 +1014,12 @@ async def remove_snapshot(request): try: target = request.rel_url.query["target"] + path = get_safe_snapshot_path(target) + + if path is None: + logging.error(f"[ComfyUI-Manager] Invalid snapshot target: {target}") + return web.Response(text="Invalid snapshot target", status=400) - path = os.path.join(core.manager_snapshot_path, f"{target}.json") if os.path.exists(path): os.remove(path) @@ -1023,8 +1036,12 @@ async def restore_snapshot(request): try: target = request.rel_url.query["target"] + path = get_safe_snapshot_path(target) + + if path is None: + logging.error(f"[ComfyUI-Manager] Invalid snapshot target: {target}") + return web.Response(text="Invalid snapshot target", status=400) - path = os.path.join(core.manager_snapshot_path, f"{target}.json") if os.path.exists(path): if not os.path.exists(core.manager_startup_script_path): os.makedirs(core.manager_startup_script_path) diff --git a/pyproject.toml b/pyproject.toml index 8e337856..e15ea6e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "comfyui-manager" description = "ComfyUI-Manager provides features to install and manage custom nodes for ComfyUI, as well as various functionalities to assist with ComfyUI." -version = "3.39.1" +version = "3.39.2" license = { file = "LICENSE.txt" } dependencies = ["GitPython", "PyGithub", "matrix-nio", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions", "toml", "uv", "chardet"]