security(api): add path traversal and CRLF injection protection
Publish to PyPI / build-and-publish (push) Has been cancelled
Python Linting / Run Ruff (push) Has been cancelled

- Add is_safe_path_target() and get_safe_file_path() utilities
- Validate history id and snapshot target parameters in API endpoints
- Sanitize config string values to prevent CRLF injection
This commit is contained in:
Dr.Lt.Data
2026-01-08 18:35:03 +09:00
parent a4138a89ee
commit ef8703a3d7
7 changed files with 92 additions and 19 deletions
+19 -5
View File
@@ -1294,11 +1294,17 @@ async def get_history(request):
try:
# Handle file-based batch history
if "id" in request.rel_url.query:
json_name = request.rel_url.query["id"] + ".json"
batch_path = os.path.join(context.manager_batch_history_path, json_name)
history_id = request.rel_url.query["id"]
# Prevent path traversal attacks
batch_path = security_utils.get_safe_file_path(history_id, context.manager_batch_history_path)
if batch_path is None:
logging.warning(f"[Security] Invalid history id rejected: {history_id}")
return web.Response(text="Invalid history id", status=400)
logging.debug(
"[ComfyUI-Manager] Fetching batch history: id=%s",
request.rel_url.query["id"],
history_id,
)
with open(batch_path, "r", encoding="utf-8") as file:
@@ -1520,7 +1526,11 @@ async def remove_snapshot(request):
try:
target = request.rel_url.query["target"]
path = os.path.join(context.manager_snapshot_path, f"{target}.json")
path = security_utils.get_safe_file_path(target, context.manager_snapshot_path)
if path is None:
logging.warning(f"[Security] Invalid snapshot target rejected: {target}")
return web.Response(text="Invalid target", status=400)
if os.path.exists(path):
os.remove(path)
@@ -1538,7 +1548,11 @@ async def restore_snapshot(request):
try:
target = request.rel_url.query["target"]
path = os.path.join(context.manager_snapshot_path, f"{target}.json")
path = security_utils.get_safe_file_path(target, context.manager_snapshot_path)
if path is None:
logging.warning(f"[Security] Invalid snapshot target rejected: {target}")
return web.Response(text="Invalid target", status=400)
if os.path.exists(path):
if not os.path.exists(context.manager_startup_script_path):
os.makedirs(context.manager_startup_script_path)