Back to skill

Security audit

ComfyUI Image & Video Generation

Security checks for vulnerabilities and agentic risk

Overview

The skill’s local ComfyUI purpose is coherent, but its script allows under-disclosed remote endpoints and unsafe file path handling that could expose prompts, input images, or readable local files if the endpoint is malicious or misconfigured.

Review this skill before installing. Use it only with a trusted local ComfyUI server, avoid setting COMFYUI_URL or --url to remote hosts, do not process sensitive source images unless you accept that they may be copied into ~/ComfyUI/input, and be cautious with output paths until filename containment checks are added. For installation, prefer pinned commits, verified model checksums, and an unprivileged account.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate.py:14
Finding
Arbitrary ComfyUI endpoint allows SSRF and disclosure of prompts and input images<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate.py:14, 45-59, 64-68, 181-205, 267, 282, 296` **Vulnerability Type**: Unrestricted server endpoint / server-side request forgery **Risk Level**: High ### Vulnerable Code ```python COMFYUI_URL = os.environ.get("COMFYUI_URL", "http://127.0.0.1:8188") ``` ```python def check_server(url=COMFYUI_URL): try: urllib.request.urlopen(f"{url}/system_stats", timeout=5) return True except Exception: return False def submit_prompt(workflow, url=COMFYUI_URL): data = json.dumps({"prompt": workflow}).encode("utf-8") req = urllib.request.Request(f"{url}/prompt", data=data, headers={"Content-Type": "application/json"}) resp = urllib.request.urlopen(req, timeout=30) return json.loads(resp.read()).get("prompt_id") ``` ```python def wait_for_completion(prompt_id, timeout=300, url=COMFYUI_URL): start = time.time() while time.time() - start < timeout: time.sleep(2) try: resp = urllib.request.urlopen(f"{url}/history/{prompt_id}", timeout=10) ``` ```python def upload_image(image_path, url=COMFYUI_URL): """Upload an image to ComfyUI input directory via API.""" if not os.path.exists(image_path): raise FileNotFoundError(f"Image not found: {image_path}") filename = os.path.basename(image_path) with open(image_path, "rb") as f: boundary = "----ComfyUIFormBoundary" body = ( f"--{boundary}\r\n" f'Content-Disposition: form-data; name="image"; filename="{filename}"\r\n' f"Content-Type: image/png\r\n\r\n" ).encode() + f.read() + f"\r\n--{boundary}--\r\n".encode() req = urllib.request.Request( f"{url}/upload/image", data=body, headers={"Content-Type": f"multipart/form-data; boundary={boundary}"}) try: urllib.request.urlopen(req, timeout=10) except Exception: pass return file ...[truncated 2319 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `--url` for normal Skill operation and force the endpoint to `http://127.0.0.1:8188`. 2. If endpoint configurability is required, parse it with `urllib.parse.urlsplit()` and enforce an explicit allowlist: - Permit only `http` or `https`. - Permit only loopback addresses by default. - Reject embedded credentials, fragments, unexpected paths, and unsupported ports. - Resolve hostnames and verify that every resolved address belongs to the intended range. 3. Require an explicit opt-in flag for remote endpoints and display a warning before prompts or images are transmitted. 4. Require HTTPS and authenticated API access for any approved remote endpoint. 5. Apply outbound network controls so the Skill cannot access metadata endpoints, private subnets, or unrelated local services. 6. Document that I2V uploads the complete selected image to the configured server. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/generate.py:75
Finding
Unvalidated API response paths permit local file disclosure and output path traversal<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate.py:75-81, 97-112` **Vulnerability Type**: Path traversal and arbitrary user-readable file copying **Risk Level**: High ### Vulnerable Code ```python outputs = hist[prompt_id].get("outputs", {}) images = [] for node_out in outputs.values(): if "images" in node_out: for img in node_out["images"]: images.append({ "filename": img["filename"], "subfolder": img.get("subfolder", ""), }) return {"status": "completed", "images": images} ``` ```python def collect_images(result, output_path=None): """Collect generated images, optionally copy to output_path.""" paths = [] for img in result["images"]: sub = img["subfolder"] sub = sub.rstrip("/") + "/" if sub else "" src = os.path.join(COMFYUI_OUTPUT, sub + img["filename"]) if output_path and os.path.exists(src): if output_path.endswith(".png"): shutil.copy2(src, output_path) else: os.makedirs(output_path, exist_ok=True) shutil.copy2(src, os.path.join(output_path, img["filename"])) paths.append(output_path if output_path.endswith(".png") else os.path.join(output_path, img["filename"])) else: paths.append(src) return paths ``` ### Technical Analysis The `filename` and `subfolder` fields are obtained from the ComfyUI history response and used in filesystem paths without validation. `os.path.join()` does not prevent traversal: components such as `../../` can escape `~/ComfyUI/output`, while an absolute path can replace the intended base path in applicable combinations. When `--output` is supplied, a malicious response can make `src` reference any existing file readable by the current user. `shutil.copy2()` then copies that file to the requested output location. If the output is a directory, the untrusted `filename` is also reused in th ...[truncated 1847 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Treat every filename and subfolder received from the API as untrusted. 2. Reject absolute paths, empty filenames, null bytes, path separators in filenames, and `.` or `..` path components. 3. Resolve and verify the source path before accessing it: ```python output_root = os.path.realpath(COMFYUI_OUTPUT) src = os.path.realpath(os.path.join(output_root, subfolder, filename)) if os.path.commonpath([output_root, src]) != output_root: raise ValueError("Output path escapes ComfyUI output directory") ``` 4. Perform an equivalent canonical containment check for destination paths. 5. Generate a safe local destination filename rather than reusing a server-controlled filename. 6. Restrict accepted files to expected extensions and verify file signatures where practical. 7. Reject symbolic links or open files using descriptor-based APIs with anti-symlink protections where supported. 8. Combine these controls with strict endpoint validation so untrusted remote servers cannot supply history responses. ]]>

T08 · Insecure Dependencies

Warning
Location
README.md:19
Finding
Installation guidance relies on mutable and unverified dependencies and model artifacts<![CDATA[ ## Vulnerability Details **File Location**: `README.md:19, 30-32, 59-75, 129-175, 195` **Vulnerability Type**: Unpinned software supply chain and unverified model artifacts **Risk Level**: Medium ### Vulnerable Code ```bash pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128 ``` ```bash git clone https://github.com/comfyanonymous/ComfyUI.git cd ComfyUI pip install -r requirements.txt ``` ```python from modelscope.hub.file_download import model_file_download import os src = model_file_download('AI-ModelScope/FLUX.1-schnell', 'flux1-schnell.safetensors') os.symlink(src, 'models/unet/flux1-schnell.safetensors') src = model_file_download('AI-ModelScope/FLUX.1-schnell', 'ae.safetensors') os.symlink(src, 'models/vae/ae.safetensors') src = model_file_download('comfyanonymous/flux_text_encoders', 'clip_l.safetensors') os.symlink(src, 'models/clip/clip_l.safetensors') src = model_file_download('comfyanonymous/flux_text_encoders', 't5xxl_fp16.safetensors') os.symlink(src, 'models/clip/t5xxl_fp16.safetensors') ``` ```bash cd ~/ComfyUI && git pull pip install -r requirements.txt ``` ```python src = model_file_download( 'Wan-AI/Wan2.1-T2V-1.3B', 'diffusion_pytorch_model.safetensors' ) src = model_file_download( 'Wan-AI/Wan2.1-T2V-1.3B', 'Wan2.1_VAE.pth' ) ``` ```python from huggingface_hub import hf_hub_download path = hf_hub_download( 'Comfy-Org/Wan_2.1_ComfyUI_repackaged', 'split_files/text_encoders/umt5_xxl_fp8_e4m3fn_scaled.safetensors' ) ``` ```python src = model_file_download( 'Wan-AI/Wan2.1-I2V-14B-480P', 'models_clip_open-clip-xlm-roberta-large-vit-huge-14.pth' ) ``` ```bash pip install imageio imageio-ffmpeg ``` ### Technical Analysis The installation instructions clone the current head of an external repository, later update it with an unrestricted `git pull`, and install dependency sets without a reviewed lock file or required hashes. Direct package installations als ...[truncated 1898 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin ComfyUI to a reviewed immutable commit and check out that commit explicitly instead of using repository head or unrestricted `git pull`. 2. Maintain a lock file with exact dependency versions and cryptographic hashes. 3. Use `pip install --require-hashes` for reproducible dependency installation. 4. Pin model downloads to immutable repository revisions. 5. Publish and verify SHA-256 or stronger checksums for every model artifact before linking or loading it. 6. Prefer `safetensors` over `.pth` whenever supported. 7. Where `.pth` is unavoidable, obtain it only from a verified publisher, validate its digest, and use safe weight-only loading functionality where compatible. 8. Review dependency and model updates before changing pinned versions. 9. Run ComfyUI under a dedicated, unprivileged account with narrowly scoped filesystem and network access. 10. Consider sandboxing or hardening the user service with systemd controls such as `NoNewPrivileges`, filesystem protections, and restricted write paths. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Rogue AgentSelf-Modification, Session Persistence
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (12)

Tainted flow: 'url' from os.environ.get (line 299, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
def check_server(url=COMFYUI_URL):
    try:
        urllib.request.urlopen(f"{url}/system_stats", timeout=5)
        return True
    except Exception:
        return False
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'url' from os.environ.get (line 299, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
while time.time() - start < timeout:
        time.sleep(2)
        try:
            resp = urllib.request.urlopen(f"{url}/history/{prompt_id}", timeout=10)
            hist = json.loads(resp.read())
            if prompt_id in hist:
                status = hist[prompt_id].get("status", {})
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

External Script Fetching

High
Category
Supply Chain
Content
systemctl --user status comfyui.service

# Check API
curl -s http://127.0.0.1:8188/system_stats | python3 -m json.tool

# Manual start (if systemd not available)
cd ~/ComfyUI && LD_LIBRARY_PATH=~/comfyui-venv/lib/python3.12/site-packages/nvidia/cuda_runtime/lib:$LD_LIBRARY_PATH ~/comfyui-venv/bin/python main.py --listen 127.0.0.1 --port 8188
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The README forces a specific language for all instructions and operational guidance, which can violate language/locale policy when no user opt-in or alternative is provided. There is no indication that the skill is intentionally limited to a Chinese-only audience or region-specific compliance context.

Session Persistence

Medium
Category
Rogue Agent
Content
cd ~/ComfyUI

# 创建目录
mkdir -p models/unet models/vae models/clip

# 下载 Flux1-schnell(使用 ModelScope Python API)
python3 -c "
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
cd ~/ComfyUI

# 创建目录
mkdir -p models/unet models/vae models/clip

# 下载 Flux1-schnell(使用 ModelScope Python API)
python3 -c "
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
EOF

systemctl --user daemon-reload
systemctl --user enable --now comfyui.service
```

---
Confidence
80% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

External Transmission

Medium
Category
Data Exfiltration
Content
## 5. 测试文生图

```bash
curl -X POST http://127.0.0.1:8188/prompt \
  -H "Content-Type: application/json" \
  -d '{"prompt": {... Flux workflow ...}}'
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill documents capabilities to read environment state, write output files, and interact with a local HTTP API, but it declares no explicit tool scope or permissions boundary. That mismatch can cause an agent platform to grant broader-than-expected capabilities or leave reviewers unaware of the real attack surface, increasing the risk of unintended file writes or service interaction.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
In image-to-video mode, the script silently copies the supplied image into ~/ComfyUI/input before processing. This creates an unexpected persistence/privacy issue because user-provided local images are duplicated into another directory without explicit notice, potentially exposing sensitive files to other local users, later workflows, or accidental retention.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The script uploads the user-specified image to the configured ComfyUI API endpoint over plain HTTP by default and without an explicit user-facing warning. In the default localhost case this is lower risk, but if COMFYUI_URL or --url points to a remote host, sensitive local images may be transmitted off-machine without clear consent or transport protection.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
This markdown file contains user-facing instructional content exclusively in Chinese, and there is no indication that the skill is region-specific or that users may opt into another language. Under the language/locale policy rule, forcing a specific language without opt-in is a natural-language policy concern.

Static analysis

No suspicious patterns detected.