Someone left the loading dock unlocked, and the forklift runs any package you hand it — no ID check required
CVE-2026-68771 is an unsafe-deserialization-to-RCE in ComfyUI ≤ v0.23.0. The LoadTrainingDataset node in comfy_extras/nodes_dataset.py calls torch.load() without setting weights_only=True, meaning any attacker who can reach the ComfyUI API can upload a malicious shard_*.pkl file via the unauthenticated POST /upload/image endpoint, then trigger its deserialization through POST /prompt — executing arbitrary Python as the ComfyUI process user. On PyTorch < 2.6 (where weights_only defaults to False), this is a textbook pickle-to-shell chain. Two HTTP requests, zero authentication, full host compromise. All versions through v0.23.0 are affected; the fix (commit 94ee49b, PR #14543) landed June 18, 2026 and shipped in v0.26.0.
The vendor CVSS 3.1 of 9.8 CRITICAL is technically accurate *for an instance listening on a routable address* — the attack surface is unauthenticated, low-complexity, and high-impact across all three CIA pillars. But CVSS doesn't model deployment posture, and ComfyUI's default bind address is 127.0.0.1. The --listen flag must be explicitly set to expose the API beyond localhost. Censys found ~1,000 confirmed-exposed instances globally in April 2026 (Shodan shows ~2,800 with port open, many behind auth or honeypots). That is a small population relative to the millions of ComfyUI installs running locally. ComfyUI is also not enterprise-critical infrastructure — it is an AI image-generation tool, not a domain controller or identity provider. The severity is real and the exploit is trivial *when reachable*, but calling every ComfyUI install CRITICAL overstates the fleet-wide risk for most organizations.
5 steps from start to impact.
Identify exposed ComfyUI instance
title:"ComfyUI" returns ~2,800 results. No special tooling beyond masscan/httpx is needed.- ComfyUI instance is bound to a routable address via
--listenflag - Port 8188 (or reverse-proxy port) is reachable from the internet or attacker's network
- Default bind is
127.0.0.1— explicit opt-in to exposure required - Enterprise deployments behind reverse proxy with auth are not reachable
- Censys confirmed only ~1,000 truly exposed instances globally
shodan search title:ComfyUI or Censys search for services.http.response.body:ComfyUI.Craft malicious pickle payload
__reduce__ to execute arbitrary shell commands on deserialization. This is a well-understood technique with public tooling (e.g., fickling, pickletools, or hand-rolled __reduce__ payloads). The file must be named shard_*.pkl to match the LoadTrainingDataset node's expected filename pattern. Proof-of-concept code is publicly available on GitHub.- Basic Python knowledge and familiarity with pickle serialization
- None — pickle RCE payloads are trivial to construct and widely documented
Upload malicious payload via /upload/image
POST /upload/image request with the crafted shard_*.pkl file. ComfyUI's upload endpoint requires no authentication and accepts arbitrary files. The file is stored in the ComfyUI input directory, ready to be referenced by a workflow. This endpoint was designed for image uploads but performs no file-type validation.- Network access to the ComfyUI API
- None once instance is reachable — endpoint is completely unauthenticated
- A WAF inspecting uploads for pickle magic bytes could block this, but ComfyUI is rarely behind a WAF
Trigger deserialization via /prompt
POST /prompt request containing a workflow JSON that includes a LoadTrainingDataset node referencing the uploaded pickle file. ComfyUI's execution engine loads the workflow, calls torch.load() on the referenced .pkl file without weights_only=True, and Python's pickle module executes the __reduce__ payload. Arbitrary code now runs as the ComfyUI process user — typically a non-root user with GPU access.- The uploaded .pkl file must be named to match the LoadTrainingDataset shard pattern
- PyTorch version < 2.6, or PyTorch ≥ 2.6 not enforcing weights_only by default on this code path
- PyTorch ≥ 2.6 defaults
weights_only=True, which would block this unless the code explicitly overrides — but the vulnerable code does NOT pass the parameter, so PyTorch's default applies - Many cloud/Docker ComfyUI images pin PyTorch < 2.6 for CUDA compatibility
Post-exploitation: host compromise
curl http://169.254.169.254/...), deploy rootkits (LD_PRELOAD hooks), establish persistence via cron/systemd, or pivot laterally within the hosting environment via Docker sockets or Redis instances.- Successful code execution from step 4
- Container isolation (if ComfyUI runs in a hardened container) limits blast radius
- Cloud IAM instance profiles with minimal permissions reduce credential value
- EDR on the host should detect post-exploitation behaviors (miner binaries, rootkit installation)
--listen 0.0.0.0, revert to the default 127.0.0.1 bind or use --listen 127.0.0.1 explicitly. This eliminates the network attack vector entirely. For remote access, use SSH tunneling or a VPN. Deploy within the noisgate mitigation SLA of 30 days for HIGH severity. This is the single most effective control — it removes the AV:N prerequisite completely.PR:L or PR:H to the attack path — the attacker must have valid credentials before reaching /upload/image or /prompt. Deploy within the noisgate mitigation SLA of 30 days.94ee49b which adds weights_only=True to the torch.load() call in LoadTrainingDataset. This is the definitive remediation. Apply within the noisgate remediation SLA of 180 days for HIGH severity. If running from git, git pull and verify the commit is present.weights_only default to True, which blocks unsafe pickle deserialization even without the ComfyUI code fix. This is a defense-in-depth measure — do not rely on it as the sole control since future PyTorch API changes could alter behavior. Combine with the ComfyUI upgrade.- WAF rules for pickle detection — pickle payloads can be trivially obfuscated or embedded in multipart form uploads that most WAFs do not deeply inspect. The
/upload/imageendpoint accepts binary file uploads, making signature-based WAF detection unreliable. - Disabling the LoadTrainingDataset node — while this removes *this specific* attack path, ComfyUI's architecture allows custom nodes to introduce similar deserialization issues. The GHOST campaign exploited entirely different nodes (FL_CodeNode, SrlEval). Removing one node is whack-a-mole, not a security strategy.
- Container isolation alone — running ComfyUI in Docker limits blast radius but does NOT prevent initial compromise. The attacker still gets code execution inside the container, can mine crypto using the GPU passthrough, and may access cloud IMDS if the container is not configured with
--network=noneor IMDSv2 hop limit.
The supporting signals.
| In-the-Wild Exploitation | No confirmed exploitation of CVE-2026-68771 specifically. However, the GHOST campaign (discovered March 2026 by Censys ARC) actively targets exposed ComfyUI instances for cryptomining/proxy botnets using *different* attack vectors (malicious custom nodes, ComfyUI-Manager misconfigs). The attacker ecosystem and scanning infrastructure to mass-exploit ComfyUI already exists — this CVE provides a cleaner, built-in-node attack path. Not listed on CISA KEV. |
|---|---|
| Proof-of-Concept | Public PoC available. Listed on poc-in-github and referenced in the KSEC Community Forum exploit feed. The exploit is trivial — a standard Python pickle __reduce__ payload uploaded via two unauthenticated HTTP requests. Tools like fickling can generate payloads automatically. |
| EPSS | 0.01148 (1.15%) — low probability of exploitation in the next 30 days per FIRST EPSS model. Reflects the small exposed population rather than exploit difficulty. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H = 9.8 CRITICAL. Every base metric is at maximum severity. The vector is technically accurate for a reachable instance but does not capture the default-localhost deployment posture. |
| Affected Versions | ComfyUI ≤ v0.23.0 (all versions through v0.23.0). The vulnerable code was introduced when the LoadTrainingDataset node was added to comfy_extras/nodes_dataset.py. Affects installs running PyTorch < 2.6 (where weights_only defaults to False). PyTorch ≥ 2.6 changed the default to True, which *may* mitigate on some installs — but the code never explicitly passed the parameter, so behavior depends on PyTorch version. |
| Fixed Version | v0.26.0 (released 2026-06-23). Fix commit 94ee49b via PR #14543, merged 2026-06-18 by mattmillerai, approved by comfyanonymous. The fix adds weights_only=True to the torch.load() call. Note: v0.24.0 (June 3) and v0.25.0 (June 16) do not contain the fix. |
| Scanning / Exposure | Censys: ~1,000 confirmed unauthenticated instances (April 2026, after filtering honeypots). Shodan: ~2,800 results for title:"ComfyUI", ~800 behind login screens. GHOST campaign scanner found ~624 live instances per scan cycle across AWS, GCP, and Oracle Cloud IP ranges. |
| Disclosure Timeline | 2026-07-31: CVE published (NVD). 2026-08-01: GHSA-6p72-9j26-4rmx published. Fix was proactively committed 2026-06-18, ~6 weeks before public CVE disclosure. |
| Researcher | Bofei Chen (credited by VulnCheck advisory). Fix PR authored by mattmillerai. |
| Related Campaigns | GHOST v5.1–v6.0 cryptomining/proxy botnet campaign (March–April 2026) — targets ComfyUI instances via malicious custom nodes and ComfyUI-Manager. Operated from Aeza Group bulletproof hosting (77.110.96.200), C2 on China Mobile (120.241.40.237). Deploys XMRig, lolMiner, Hysteria v2 proxy. Uses fileless execution, LD_PRELOAD rootkit, three persistence mechanisms. See Censys blog and CSA research note. |
Sources.
- GHSA-6p72-9j26-4rmx — GitHub Security Advisory
- Fix PR #14543 — ComfyUI GitHub
- Fix Commit 94ee49b — ComfyUI GitHub
- Censys ARC — ComfyUI Cryptomining Proxy Botnet
- The Hacker News — 1,000+ Exposed ComfyUI Instances
- VulnCheck Advisory — ComfyUI Unauthenticated RCE
- CSA Research Note — AI Workload Exposure Cryptomining
- Rapid7 Vulnerability Database — CVE-2026-68771
Why this verdict
- Default localhost binding is a hard friction gate. ComfyUI binds to
127.0.0.1by default. The--listenflag must be explicitly passed to expose the API. This means the vast majority of installations — personal workstations, local dev setups, Docker containers without port mapping — are unreachable. The 9.8 CVSS assumesAV:Nis universally true, but it requires a deliberate configuration change. - Small exposed population limits blast radius. Censys confirmed ~1,000 unauthenticated instances globally; Shodan shows ~2,800 total. Against millions of ComfyUI installs running locally, the reachable attack surface is <0.1% of the installed base. Enterprise environments with ComfyUI are more likely to run it behind reverse proxies with authentication.
- Trivially weaponizable when reachable — holds the floor at HIGH. The attack requires exactly two unauthenticated HTTP requests, public PoC exists, and the GHOST campaign proves attackers are already mass-scanning for ComfyUI. Zero friction once the instance is reachable. This prevents further downgrade below HIGH.
- Role multiplier: ComfyUI is not in the high-value-role catalog. ComfyUI is an AI image-generation application, not an identity provider, domain controller, hypervisor, backup system, CI/CD pipeline, or network edge appliance. It is never canonically deployed in a fleet-defining role. The blast radius of a compromised instance is host-level (GPU server compromise, potential cloud credential theft via IMDS), not domain-level or supply-chain-level. However, GPU hosts in cloud environments may carry IAM roles with meaningful permissions, and compromised instances have intrinsic value for cryptomining — this keeps the floor at HIGH rather than MEDIUM.
- Active attacker ecosystem. While the GHOST campaign uses different vectors (malicious custom nodes), its scanning infrastructure covers the same target population. CVE-2026-68771 provides a cleaner attack path using a *built-in* node rather than requiring custom node installation. The established attacker tooling and economic incentive (GPU-rich hosts for mining) make exploitation of this CVE in the wild a near-certainty for exposed instances.
Why not higher?
CRITICAL would require either a canonically high-value-role component (ComfyUI is not one — it is an AI image generation tool, not infrastructure) or a universally reachable attack surface. The default localhost binding means the overwhelming majority of installations are never exposed to this vulnerability. The ~1,000 exposed instances represent a tiny fraction of the installed base, and the blast radius is host-level, not domain or fleet-level. No KEV listing and EPSS of 1.15% further confirm this is not a CRITICAL-tier fleet emergency.
Why not lower?
MEDIUM would understate the risk for the population that IS exposed. When a ComfyUI instance is reachable, exploitation is trivial — two HTTP requests, no auth, no user interaction, public PoC, and an established attacker ecosystem already targeting these hosts. GPU servers in cloud environments carry real value (IAM credentials, expensive compute for cryptomining). The GHOST campaign proves this is not theoretical. Any organization with internet-facing ComfyUI instances faces immediate, practical risk.
Crowdsourced verification payload.
Run this script on each host running ComfyUI as any user with read access to the ComfyUI installation directory. Pass the ComfyUI install path as the first argument: bash check_cve_2026_68771.sh /opt/ComfyUI. No elevated privileges required.
#!/usr/bin/env bash
# check_cve_2026_68771.sh — Detect CVE-2026-68771 (ComfyUI LoadTrainingDataset pickle RCE)
# Usage: bash check_cve_2026_68771.sh /path/to/ComfyUI
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
COMFY_DIR="${1:-}"
if [[ -z "$COMFY_DIR" ]]; then
echo "Usage: $0 /path/to/ComfyUI"
exit 2
fi
TARGET_FILE="${COMFY_DIR}/comfy_extras/nodes_dataset.py"
# Check if the file exists
if [[ ! -f "$TARGET_FILE" ]]; then
echo "UNKNOWN — $TARGET_FILE not found. ComfyUI may not be installed at this path, or the LoadTrainingDataset node may not be present."
exit 2
fi
# Check for the vulnerable pattern: torch.load() without weights_only=True
# The fix changed: torch.load(f) -> torch.load(f, weights_only=True)
if grep -qP 'torch\.load\s*\(\s*f\s*\)' "$TARGET_FILE"; then
echo "VULNERABLE — $TARGET_FILE contains torch.load(f) without weights_only=True."
echo " CVE-2026-68771: Unsafe deserialization in LoadTrainingDataset node."
echo " Fix: Upgrade ComfyUI to v0.26.0+ or apply commit 94ee49b."
# Bonus: check if ComfyUI is listening on a non-localhost address
if pgrep -af 'python.*main.py.*--listen' 2>/dev/null | grep -qv '127.0.0.1'; then
echo " WARNING: ComfyUI appears to be running with --listen (network-exposed). IMMEDIATE risk."
fi
exit 1
fi
if grep -qP 'torch\.load\s*\(.*weights_only\s*=\s*True' "$TARGET_FILE"; then
echo "PATCHED — $TARGET_FILE contains torch.load() with weights_only=True."
echo " CVE-2026-68771 is mitigated."
exit 0
fi
echo "UNKNOWN — Could not determine patch status. Manual review of $TARGET_FILE recommended."
exit 2