T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/comfy_gen.py:111
- Finding
- Server-Controlled Path Traversal Enables Arbitrary File Overwrite## Vulnerability Details **File Location**: `scripts/comfy_gen.py`, lines 111–114 **Vulnerability Type**: Path traversal and arbitrary file overwrite **Risk Level**: High ### Vulnerable 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 `filename` value 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 intended `image-gens/` directory. A malicious or compromised ComfyUI server can return a filename containing traversal components, such as `../../.bashrc`. Concatenating that value produces `image-gens/../../.bashrc`, allowing `urlretrieve()` 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 1. A user configures the Skill to use an attacker-controlled or compromised ComfyUI server. 2. The script submits a workflow to the server and obtains a valid `prompt_id`. 3. During history polling, the server returns an image record with a traversal filename such as `../../.bashrc`. 4. The script constructs `image-gens/../../.bashrc` without validation. 5. The script requests the server-controlled `/view` resource and writes its response to the traversed path. 6. The target file is created or overwritten if the running account has sufficient filesystem permissions. 7. If the selected target is a sta ...[truncated 758 chars]
- Remediation
- ## Remediation Suggestions Treat all response fields from the ComfyUI server as untrusted input. 1. Generate a trusted local filename rather than reusing the server-provided filename whenever possible. 2. If the original name must be retained, remove all directory components using `os.path.basename()` or `Path(filename).name`. 3. Resolve both the output directory and candidate destination, then verify that the candidate is a descendant of the output directory. 4. Reject empty filenames, absolute paths, traversal components, unexpected extensions, and malformed names. 5. Download into a securely created temporary file and atomically move it to the validated destination. 6. Consider refusing to overwrite existing files. 7. 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.
