Back to skill

Security audit

ComfyUI

Security checks for vulnerabilities and agentic risk

Overview

This ComfyUI skill has a coherent image-workflow purpose, but it needs Review because it can automatically install and run unverified external software and accepts arbitrary model URLs with unsafe file and network handling.

Review this skill before installing. Use it only if you trust the ComfyUI environment and the model URLs, avoid untrusted workflow JSON or pasted URL lists, prefer --no-pget unless pget is already installed from a trusted source, and pin/verify ComfyUI and model downloads where possible.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/download_weights.py:108
Finding

Encoded Path Traversal Allows Writes Outside the ComfyUI Models Directory

Content
View full analysis
tuple[str | None, str | None, bool]: """Return (url, dest_path, is_skip). url None = skip/ignore.""" url = raw.strip() if not url or url.startswith("#"): return (None, None, True) subfolder = default_subfolder if default_subfolder in SUBFOLDERS else "checkpoints" if " " in url: url, sub = url.strip().split(None, 1) sub = sub.strip().lower() if sub in SUBFOLDERS: subfolder = sub elif not default_subfolder or default_subfolder not in SUBFOLDERS: subfolder = infer_subfolder(url) base = os.path.expanduser(base) model_dir = os.path.join(base, "models", subfolder) os.makedirs(model_dir, exist_ok=True) path = urlparse(url).path name = path.rstrip("/").split("/")[-1] name = unquote(name) if name else "downloaded.safetensors" out_path = os.path.join(model_dir, name) if os.path.isfile(out_path) and not overwrite: return (None, out_path, True) return (url, out_path, False) ``` The resulting path is subsequently used as a file-write destination: ```python def download_one_fallback( url: str, dest_path: str, overwrite: bool ) -> tuple[str, str]: """Download one file with urllib. Returns (status, path_or_message).""" if os.path.isfile(dest_path) and not overwrite: return ("skipped", dest_path) req = urllib.request.Request(url, headers={"User-Agent": "ComfyUI-Skill/1.0"}) try: with urllib.request.urlopen(req, timeout=600) as resp: with open(dest_path, "wb") as f: while True: chunk = resp.read(1 << 20) if not chunk: break ...[truncated 2324 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/download_weights.py:108
Finding

Unrestricted Download URLs Enable SSRF and Local Resource Retrieval

Content
View full analysis
Remediation
View remediation

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/download_weights.py:22
Finding

Unpinned Remote Binary Is Downloaded, Marked Executable, and Run Without Integrity Verification

Content
View full analysis
str | None: """Return path to pget binary, or None if not found and install failed.""" pget = shutil.which("pget") if pget: return pget # Install to ~/.local/bin local_bin = os.path.expanduser("~/.local/bin") pget_path = os.path.join(local_bin, "pget") if os.path.isfile(pget_path) and os.access(pget_path, os.X_OK): return pget_path os.makedirs(local_bin, exist_ok=True) sysname = platform.system() machine = platform.machine() if machine == "aarch64": machine = "arm64" elif machine == "x86_64": machine = "x86_64" # Replicate releases: pget_Linux_x86_64, pget_Darwin_arm64, etc. asset = f"pget_{sysname}_{machine}" url = f"{PGET_RELEASE}/{asset}" try: req = urllib.request.Request(url, headers={"User-Agent": "ComfyUI-Skill/1.0"}) with urllib.request.urlopen(req, timeout=60) as resp: with open(pget_path, "wb") as f: f.write(resp.read()) os.chmod(pget_path, 0o755) return pget_path except Exception as e: print(f"Could not install pget ({e}); falling back to built-in download.", file=sys.stderr) return None ``` The downloaded file is subsequently executed: ```python def download_with_pget(manifest_path: str, pget_bin: str, overwrite: bool) -> bool: cmd = [pget_bin, "multifile", manifest_path] if overwrite: cmd.append("-f") r = subprocess.run(cmd) return r.returncode == 0 ``` ### Technical Analysis When `pget` is absent, the script downloads a native executable from a mutable `latest` release URL, writes it to `~/.local/bin/pget`, g ...[truncated 1936 chars]
Remediation
View remediation

T03 · Remote Payload Retrieval and Execution

Warning
Location
SKILL.md:60
Finding

ComfyUI Installation Instructions Clone and Install Unpinned Upstream Code

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (12)

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · CONTRIBUTING.md (reported line 48)May include surrounding context.

md
## Updating the Skill

- When ComfyUI’s API or workflow format changes, update SKILL.md and the run script.
- Keep the “If the server isn’t reachable” section in sync with current ComfyUI install/run instructions.
- Bump version when publishing a new release to ClawHub.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The declared purpose is local workflow execution, but the instructions also authorize downloading arbitrary remote files, installing an external binary into the user's home directory, and writing into model directories. This mismatch is dangerous because users or orchestration systems may invoke the skill for innocuous image generation while unintentionally triggering software installation or remote file retrieval with significant system side effects.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script automatically downloads an external executable from GitHub and then later executes it, creating a clear supply-chain risk. If the release asset, transport, account, or upstream project is compromised, this skill can introduce and run arbitrary code on the host under the user's account.

Content

No source excerpt is available for this finding.

Self-Modification

High
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Content

Scanner excerpt · scripts/download_weights.py (reported line 173)May include surrounding context.

python
ap.add_argument(
        "--overwrite",
        action="store_true",
        help="Overwrite existing files",
    )
    ap.add_argument(
        "--no-pget",

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill instructs the agent to read local files, invoke shell commands, and access the network, but it declares no explicit tool scope or permission boundary. That increases the chance the agent will use powerful capabilities implicitly and without user-visible guardrails, especially when handling user-supplied workflow paths and URLs.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The read_when conditions include generic image-generation prompts, which can cause this high-privilege skill to trigger for broad, ordinary requests. In context, that is risky because the skill can read arbitrary workflow files, make network requests, and modify local state, so over-broad matching expands the attack surface for accidental or adversarial activation.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
84% confidence
Finding

The skill tells the agent to write edited workflows to a persistent path under the skill assets directory, which can leave behind user-derived prompts, seeds, and workflow modifications across sessions. While not inherently malicious, this creates session persistence and possible cross-user data leakage or stale-state reuse if later runs consume the leftover file.

Content

Scanner excerpt · SKILL.md (reported line 25)May include surrounding context.

md
2. **Identify prompt-related nodes** by inspecting the graph: look for nodes that hold the main text prompt — e.g. `PrimitiveStringMultiline`, `CLIPTextEncode` (positive text), or any node with `_meta.title` or `class_type` suggesting "Prompt" / "positive" / "text". Update the corresponding input (e.g. `inputs.value`, or the text input to the encoder) to the image prompt you derived from the user (subject, style, lighting, quality). If the user didn’t ask for a custom image, you can leave the existing prompt or tweak only if needed.
3. **Optionally identify style/prefix nodes** — e.g. `StringConcatenate`, or a second string input that acts as style. Set them if the user asked for a specific style or to clear a default prefix.
4. **Optionally set a new seed** — find sampler-like nodes (e.g. `KSampler`, `BasicGuider`, or any node with a `seed` input) and set `seed` to a new random integer so each run can differ.
5. Write the modified workflow to a temp file (e.g. `skills/comfyui/assets/tmp-workflow.json`). Use `~/ComfyUI/venv/bin/python` for any inline Python; do not use bare `python`.
6. Run: `comfyui_run.py --workflow <path-to-edited-json>`.

If the workflow structure is unclear or you can’t find prompt/sampler nodes, run the file as-is and only change what you can reliably identify. Same approach for arbitrary user-supplied JSON: inspect first, edit at your best knowledge, then run.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill directs the agent to clone a repository, install dependencies, download model weights from arbitrary URLs, and potentially install pget, yet it does not require an explicit warning or confirmation about network, execution, disk, and persistence side effects. That is dangerous because a user may believe they are only generating an image while the agent performs software installation and fetches untrusted content onto the host.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script adds a capability to fetch remote model weights and modify the local ComfyUI installation, which exceeds the declared scope of a skill meant to run local ComfyUI workflows via HTTP. This scope expansion matters because it introduces network access, remote content ingestion, and filesystem writes that users and reviewers may not expect from the skill metadata.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/download_weights.py (reported line 127)May include surrounding context.

python
cmd = [pget_bin, "multifile", manifest_path]
    if overwrite:
        cmd.append("-f")
    r = subprocess.run(cmd)
    return r.returncode == 0

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The markdown states that the agent will edit workflow JSON and write a temporary workflow file, which affects files on disk. The description does not include any caution or user-facing warning about this file-writing behavior or where the modified file will be stored/overwritten.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The workflow includes natural-language prompt content that explicitly specifies "Latina female" as the generated subject. This bakes a demographic choice into the skill behavior without offering user opt-in or indicating that the workflow is intentionally region- or audience-specific, which can violate organizational language/policy expectations around user choice.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.