Back to skill

Security audit

Comfyui Local

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its stated ComfyUI image-generation purpose, but a malicious or compromised ComfyUI server could make it write files outside the intended output folder.

Review before installing. Use this only with a ComfyUI server you control and trust, because the current downloader trusts server-provided filenames. The publisher should validate or replace returned filenames and enforce that all downloaded files stay under the skill's output directory before this is treated as low risk.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/comfy_gen.py:151
Finding

Arbitrary File Write Through Server-Controlled Image Filename

Content
View full analysis

Vulnerability Details

File Location: scripts/comfy_gen.py, lines 151–164 and 326–334
Vulnerability Type: Path traversal leading to arbitrary file creation or overwrite
Risk Level: High

Vulnerable Code

python
def download_image(server: str, filename: str, subfolder: str, folder_type: str) -> Path:
    """Download a generated image from ComfyUI."""
    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
    
    params = urllib.parse.urlencode({
        "filename": filename,
        "subfolder": subfolder,
        "type": folder_type,
    })
    url = f"{server}/view?{params}"
    image_path = OUTPUT_DIR / filename
    
    try:
        urllib.request.urlretrieve(url, str(image_path))

The untrusted filename reaches this function from the ComfyUI server response:

python
for node_id, node_output in outputs.items():
    if "images" in node_output:
        for image_data in node_output["images"]:
            image_path = download_image(
                SERVER_ADDRESS,
                image_data["filename"],
                image_data.get("subfolder", ""),
                image_data.get("type", "output"),
            )

Technical Analysis

The filename value is obtained from the remote ComfyUI history response and used directly as the local destination path:

python
image_path = OUTPUT_DIR / filename

No validation rejects absolute paths, directory separators, or traversal components such as ... Joining a base directory with a value such as ../../target-file does not guarantee that the resulting path remains under OUTPUT_DIR.

The subsequent urlretrieve call writes server-supplied response content to that unchecked path. Therefore, a compromised or malicious configured ComfyUI server can control both the destination filename and the bytes written there.

This behavior exceeds the minimum privileges required for image generation. The Skil ...[truncated 1785 chars]

Remediation
View remediation

Remediation Suggestions

  1. Treat every filename returned by the ComfyUI server as untrusted.

  2. Reject absolute paths, .. components, and both POSIX and Windows path separators.

  3. Resolve the destination path and enforce containment with Path.is_relative_to():

    python
    safe_name = Path(filename).name
    if safe_name != filename or not safe_name:
        raise ValueError("Invalid server-provided filename")
    
    output_root = OUTPUT_DIR.resolve()
    image_path = (output_root / safe_name).resolve()
    
    if not image_path.is_relative_to(output_root):
        raise ValueError("Image path escapes the output directory")
    
  4. Prefer generating a local random filename rather than trusting the server-provided name:

    python
    import uuid
    
    image_path = OUTPUT_DIR / f"{uuid.uuid4().hex}.png"
    
  5. Download to a temporary file inside OUTPUT_DIR, validate the maximum size and expected image format, and then atomically rename it.

  6. Avoid following existing symbolic links when creating the destination file. Use exclusive or no-follow file creation mechanisms where supported.

  7. Apply an explicit response-size limit to prevent disk exhaustion.

  8. Add regression tests covering absolute paths, ../ traversal, nested paths, Windows separators, symlink destinations, and malformed filenames.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (10)

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

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/comfy_gen.py (reported line 137)May include surrounding context.

python
start = time.time()
    while time.time() - start < timeout:
        try:
            with urllib.request.urlopen(f"{server}/history/{prompt_id}", timeout=10) as resp:
                history = json.loads(resp.read().decode("utf-8"))
        except urllib.error.URLError:
            time.sleep(2)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill declares network, environment-variable, and file-read/write capabilities in practice, but does not explicitly scope or declare them via permissions or allowed-tools metadata. This weakens policy enforcement and user/operator visibility, making it easier for a consuming agent platform to run the skill with broader access than intended, especially since it connects to a configurable server and writes downloaded files to disk.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

This JSON workflow defines behavior and outputs but provides no invocation description, trigger phrases, scope constraints, or exclusion conditions. For manifest-style files, the absence of any activation guidance can make it unclear when this skill should be used versus not used, which matches the vague-trigger category.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The SaveImage node persists generated images to disk via a filename prefix, which is a file-write operation. In this code/config file, there is no confirmation prompt, user-facing notice, or explanatory comment warning that files will be written, so the behavior lacks disclosure.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest describes a skill for generating images via allowlisted ComfyUI workflows, but this workflow chains generation with downscaling, a video upscaler, sharpening, film grain, and final image saving. Those operations materially expand behavior from simple image generation into enhancement/post-processing and use a component explicitly named for video upscaling.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill behavior includes downloading generated content and saving it to an output directory, but the description does not present this as a clear user-facing warning. This can lead to unexpected persistence of generated or potentially sensitive images on disk, which matters more in environments handling private prompts or shared workspaces.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill manifest context says the server address is hardcoded, and the module security design reiterates that the server address comes from an environment variable only. In code, SERVER_ADDRESS is sourced from COMFYUI_SERVER_ADDRESS at runtime, which contradicts the claimed hardcoded-address design and changes the trust boundary from fixed configuration to caller-controlled environment configuration.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The module docstring states 'No arbitrary file reads', but the script accepts a workflow name and reads the corresponding JSON file from disk after validation. While the read is constrained to an allowlisted directory and is likely safe, the documentation is still materially inaccurate because file reads do occur.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
78% confidence
Finding

The node at L201 is explicitly a "SeedVR2VideoUpscaler", while the sink at L229-L231 is titled "Save Final Image," which presents the result as a normal final image without reflecting that it was processed through a video upscaling stage. This documentation/meta naming can mislead reviewers about the workflow's true behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
87% confidence
Finding

The workflow writes output to disk via a SaveImage node without any embedded disclosure in the workflow file. In a local skill, silent persistence can surprise users, leave behind sensitive or policy-relevant generated content, and create retention/privacy issues, especially on shared systems. This is not severe, but it is a legitimate security/privacy concern because data is stored beyond the immediate session without clear notice.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.