Comfy-Org / Comfy-Org/comfy-cli
feat(cql): allow non-loopback object_info only for an explicit --host
- Dominant language
- Python
- Stars
- 968
- Forks
- 151
- Avg merge
- 1d 9h
- Merged PRs (30d)
- 77
Description
**Describe the solution you'd like**
Treat an actual per-invocation `--host` as explicit operator authorization for a local-mode, non-loopback `/object_info` fetch.
Today the affected commands expose `--host` and `--port`, but `comfy_cli.cql.engine._load_from_target()` rejects every non-loopback local target, including an explicitly supplied host:
```text
Refusing to fetch object_info from non-loopback host 'gpu-box' in local mode (potential SSRF)
```
The proposed contract is deliberately narrow:
- Capture whether `--host` was explicitly supplied before `resolve_host_port()` applies `COMFY_LOCAL_URL`, `config.background`, or defaults.
- Thread that provenance through `Graph.load()` / `resilient_load_object_info()` and both loader attempts.
- Permit a non-loopback local fetch only when the host was explicit.
- Keep the central guard fail-closed by default.
- Preserve the loopback, cloud, offline `--input`, no-redirect, response-size, timeout, and host-validation behavior.
- `--port` alone must not authorize a remote fetch.
This should apply consistently to current live-object-info commands that already expose `--host`, including both validate routes, the node discovery commands, and `workflow slots` / `set-slot` / `vary` (plus other current live-object-info commands such as workflow decomposition). Purely file-based commands must remain unaffected.
Example desired behavior:
```bash
comfy nodes search "KSampler" --host gpu-box --port 8188
comfy workflow validate workflow.json --host gpu-box --port 8188
```
A real command-level regression should prove that an explicit non-loopback target receives the request, while an ambient/default non-loopback target performs no HTTP request and remains refused.
**Describe alternatives you've considered**
1. Add a second `--allow-remote-object-info` flag. This is more explicit, but duplicates consent across every affected command and every wrapper. It remains a reasonable fallback if maintainers do not consider `--host` itself sufficient authorization.
2. Trust every resolved host. Rejected because it would weaken the existing SSRF boundary for `COMFY_LOCAL_URL`, persisted background configuration, and defaults.
3. Add host/CIDR allowlists. Rejected as disproportionate DNS, IPv4/IPv6, and configuration complexity for an explicit CLI destination.
4. Fetch `/object_info` directly in comfy-mcp. Rejected because comfy-mcp's contribution contract requires every feature to remain a `comfy` passthrough and forbids a direct HTTP client.
5. Use `--where cloud`. That selects Comfy Cloud, not a private ComfyUI GPU host.
**Additional context**
This is the missing CLI prerequisite for:
- Comfy-Org/comfy-mcp#247
- the completed but intentionally closed forwarding work in Comfy-Org/comfy-mcp#168
The MCP wrapper receives its remote target from operator environment configuration and converts it to an actual CLI `--host`; MCP tool arguments do not expose arbitrary host selection. The MCP forwarding must not merge until this contract ships in a released comfy-cli version.
SiaoZeng/comfy-cli#741 adds a separate streaming `nodes snapshot` path and does not change the CQL loader, so it is not a workaround for this issue. If both changes land, snapshot should use the same explicit-vs-ambient trust semantics rather than creating a broader exception.
Contributor guide
Research direction
Start at comfy_cli.cql.engine._load_from_target(), then trace Graph.load() and resilient_load_object_info() through both loader attempts and the live-object-info command entry points named in the issue. Done means explicit non-loopback --host requests succeed while ambient or default non-loopback targets remain refused, with command-level regression coverage and existing safety behavior preserved.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- cli, security
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 62/100