T09 · Insecure Skill Coding Practices
- Location
scripts/comfy_gen.py:111- Finding
Server-Controlled Path Traversal Enables Arbitrary File Overwrite
- Content
View full analysis
Vulnerability Details
File Location:
scripts/comfy_gen.py, lines 111–114
Vulnerability Type: Path traversal and arbitrary file overwrite
Risk Level: HighVulnerable Code
python filename = image_data['filename'] subfolder = image_data['subfolder'] folder_type = image_data['type'] # Download image image_url = f"{server_address}/view?filename={filename}&subfolder={subfolder}&type={folder_type}" image_path = f"image-gens/{filename}" os.makedirs("image-gens", exist_ok=True) urllib.request.urlretrieve(image_url, image_path)Technical Analysis
The
filenamevalue is obtained from the ComfyUI server's/history/{prompt_id}response and used directly to construct the local destination path. The code does not remove directory components, canonicalize the path, or verify that the resolved destination remains inside the intendedimage-gens/directory.A malicious or compromised ComfyUI server can return a filename containing traversal components, such as
../../.bashrc. Concatenating that value producesimage-gens/../../.bashrc, allowingurlretrieve()to write the downloaded response outside the intended output directory.Because the downloaded content is also controlled by the server, this is an arbitrary file-write primitive constrained only by the operating-system permissions of the account running the Skill.
Attack Path
- A user configures the Skill to use an attacker-controlled or compromised ComfyUI server.
- The script submits a workflow to the server and obtains a valid
prompt_id. - During history polling, the server returns an image record with a traversal filename such as
../../.bashrc. - The script constructs
image-gens/../../.bashrcwithout validation. - The script requests the server-controlled
/viewresource and writes its response to the traversed path. - The target file is created or overwritten if the running account has sufficient filesystem permissions.
- If the selected target is a sta ...[truncated 758 chars]
- Remediation
View remediation
Remediation Suggestions
Treat all response fields from the ComfyUI server as untrusted input.
- Generate a trusted local filename rather than reusing the server-provided filename whenever possible.
- If the original name must be retained, remove all directory components using
os.path.basename()orPath(filename).name. - Resolve both the output directory and candidate destination, then verify that the candidate is a descendant of the output directory.
- Reject empty filenames, absolute paths, traversal components, unexpected extensions, and malformed names.
- Download into a securely created temporary file and atomically move it to the validated destination.
- Consider refusing to overwrite existing files.
- URL-encode the remote query parameters independently.
Example hardening:
python from pathlib import Path import urllib.parse import urllib.request import uuid output_dir = Path("image-gens").resolve() output_dir.mkdir(parents=True, exist_ok=True) supplied_name = Path(str(image_data["filename"])).name extension = Path(supplied_name).suffix.lower() if extension not in {".png", ".jpg", ".jpeg", ".webp"}: raise ValueError("Unsupported image extension") safe_name = f"{uuid.uuid4().hex}{extension}" destination = (output_dir / safe_name).resolve() if destination.parent != output_dir: raise ValueError("Invalid output path") query = urllib.parse.urlencode({ "filename": image_data["filename"], "subfolder": image_data["subfolder"], "type": image_data["type"], }) image_url = f"{server_address}/view?{query}" urllib.request.urlretrieve(image_url, destination)The ComfyUI endpoint should also be restricted to trusted hosts, authenticated where supported, and accessed over a protected transport when traffic crosses an untrusted network.
