← Back to Feed CACHED · 2026-06-30 01:52:57 · CACHE_KEY CVE-2026-13493
CVE-2026-13493 · CWE-99 · Disclosed 2026-06-28

ComfyUI-Copilot Workflow Checkpoint Restore Handler — Improper Control of Resource Identifiers (CWE-99)

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

A janky filename parser in an AI workflow toy lets a logged-in user peek at files they shouldn't

CVE-2026-13493 lives in backend/controller/conversation_api.py of AIDC-AI ComfyUI-Copilot — a third-party custom node that bolts an LLM assistant onto the popular ComfyUI image-generation framework. The Workflow Checkpoint Restore Handler does improper control of resource identifiers (CWE-99): an authenticated request can manipulate a checkpoint/workflow identifier so the handler dereferences a resource the caller shouldn't reach. CVSS vector C:L/I:N/A:N confirms the impact ceiling: read-only, partial confidentiality, no integrity or availability hit. All versions 2.0.0 through 2.0.28 are affected; as of disclosure (2026-06-28) PR #150 sits unmerged, so no fixed release yet.

The vendor's LOW (3.1) rating matches reality. ComfyUI-Copilot is a hobbyist/creator-tier plugin layered on top of ComfyUI — itself rarely Internet-exposed and almost never deployed in regulated enterprise data paths. The attacker must already be an authenticated user of a Copilot instance, the attack complexity is high (AC:H), EPSS is 0.00232 (~bottom quartile), KEV is silent, and the worst outcome is leaking workflow metadata or adjacent file content — not RCE, not auth bypass, not lateral movement. There is no role-multiplier case where this component sits on a domain controller, hypervisor, or identity provider. Treat as a tracked backlog item, not an incident.

"Authenticated, high-complexity info-leak in a niche ComfyUI plugin. Vendor LOW is right; this is backlog hygiene, not a fire drill."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Locate a reachable ComfyUI-Copilot instance

Attacker enumerates ComfyUI deployments running the Copilot custom node (default ComfyUI port 8188, plus the Copilot backend route). Shodan/Censys queries for ComfyUI banners surface a few thousand hosts globally, but most are local/loopback installs by individual creators. Enterprise exposure is negligible.
Conditions required:
  • Network reachability to the Copilot backend HTTP endpoint
  • Target running ComfyUI-Copilot ≤ 2.0.28
Where this breaks in practice:
  • ComfyUI is overwhelmingly deployed on localhost or LAN by individual artists/researchers
  • Copilot is an opt-in custom node, not bundled with ComfyUI core
  • Most enterprise GenAI stacks use SDXL/Flux behind managed APIs, not ComfyUI plugins
Detection/coverage: Shodan tag comfyui + path probe /copilot works but yields a tiny pool; no vendor signature for this CVE yet
STEP 02

Obtain authenticated session

CVSS PR:L means the attacker must already hold a low-privileged authenticated session on the Copilot backend. In practice that means a stolen API token, a shared workspace credential, or a deployment that wired Copilot to internal SSO without scoping.
Conditions required:
  • Valid user credentials, API key, or hijacked session cookie
  • Knowledge of the Copilot auth flow
Where this breaks in practice:
  • ComfyUI itself has no built-in auth — many Copilot deployments either run open on LAN (no auth flow at all) or are gated by a reverse proxy that the attacker must also defeat
  • Public exposure without auth is a separate misconfiguration class, not this CVE
Detection/coverage: Auth proxy logs, anomalous token usage, rate-limiting alerts on /conversation_api routes
STEP 03

Craft malformed checkpoint identifier

Per PoC notes in the GHSA, the attacker submits a Workflow Checkpoint Restore request with a manipulated resource identifier — likely a path-traversal-flavored payload or alternative checkpoint key — that the handler in conversation_api.py accepts without normalization. CWE-99 ID-confusion classes typically resolve to reading a file or session resource the caller wasn't authorized to access.
Conditions required:
  • Working knowledge of the checkpoint restore endpoint schema (public, in repo)
  • Ability to send authenticated POST/GET to the affected route
Where this breaks in practice:
  • AC:H — the vendor flagged exploit complexity high, implying non-obvious payload shape and possibly race/state requirements
  • PoC is public but quality and reliability are unverified
Detection/coverage: WAF rules for path-traversal patterns on the Copilot route; backend access log review for unusual checkpoint IDs
STEP 04

Read unauthorized resource

Handler returns content of the targeted resource — most plausibly another user's workflow JSON, conversation history, or a local file the Copilot process can read. Impact is bounded by C:L: partial, not full disclosure; I:N/A:N rules out write or denial-of-service.
Conditions required:
  • Step 3 payload accepted by handler
  • Target resource readable by the Copilot service account
Where this breaks in practice:
  • Most Copilot installs run as an unprivileged user with read access only to the workflow/checkpoint directory
  • No path to credentials, secrets, or host filesystem beyond what the process already touches
Detection/coverage: Egress monitoring is overkill for ≤few KB workflow JSON; audit logs of restore handler if instrumented
03 · Compensating Control

1
Inventory ComfyUI-Copilot installs — Grep your AI/ML asset register and developer workstation MDM data for ComfyUI custom-node directories containing ComfyUI-Copilot. Most orgs will return zero hits; the few that do are typically R&D or marketing creative teams. No mitigation SLA applies at LOW — handle within the noisgate remediation SLA of 365 days.
2
Block Copilot backend from untrusted networks — Bind the ComfyUI/Copilot HTTP listener to localhost or place it behind an authenticating reverse proxy with per-user scoping. This kills the network-reachability prerequisite entirely for any install that doesn't strictly need remote use.
3
Scope service account file access — Run ComfyUI/Copilot as an unprivileged user whose filesystem read scope is restricted to the model/workflow directory only. Caps the worst-case CWE-99 read to data the user already has rights to.
4
Track PR #150 and pin to the fixed release — Subscribe to AIDC-AI/ComfyUI-Copilot releases. When the fix merges and a 2.0.29+ release ships, upgrade in the same maintenance window you already use for creative-tools — no out-of-band action required.
What doesn't work
  • Generic WAF deployments — most enterprises don't proxy internal AI-art tooling through a WAF, and the payload shape (resource-identifier manipulation in a custom JSON endpoint) is unlikely to match default OWASP CRS rules.
  • EDR alerts — there is no host-level execution to detect; the attack is an authenticated HTTP request returning a file read inside the Copilot process.
  • MFA — does not help once the attacker holds a valid session/token, which is the assumed starting state.
  • Network egress DLP — workflow JSON is small, mundane-looking traffic; DLP signatures will not distinguish a legitimate Copilot response from a CVE-2026-13493 leak.
04 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNone observed. No campaigns, no honeypot hits, no vendor IR notes as of 2026-06-30.
Proof-of-conceptPublic PoC referenced in the disclosure (GitHub issue #149); reliability and weaponization quality unverified.
EPSS0.00232 — roughly the ~50th percentile; FIRST's model expects effectively zero exploitation activity over the next 30 days.
KEV statusNot listed. CISA has not added CVE-2026-13493 to the Known Exploited Vulnerabilities catalog.
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:L/I:N/A:N → network-reachable but high-complexity, authenticated, read-only partial disclosure.
Affected versionsAIDC-AI ComfyUI-Copilot 2.0.0 through 2.0.28 (all releases prior to a forthcoming fix).
Fixed versionNone released as of 2026-06-30. Fix is proposed in PR #150, awaiting maintainer merge.
Exposure dataShodan/Censys queries for ComfyUI instances return a few thousand hosts globally; the Copilot custom node is an opt-in subset, and almost none are enterprise-managed. Enterprise blast radius effectively <0.01% of typical Fortune 1000 fleets.
DisclosurePublished 2026-06-28 via GitHub Security Advisory GHSA-CJXX-6MF8-HQMW.
ReporterDisclosed via the AIDC-AI ComfyUI-Copilot project GitHub issue tracker; no named external researcher in the advisory.

Sources.

  1. Vulnerability-Lookup: CVE-2026-13493
  2. Vulnerability-Lookup: GHSA-CJXX-6MF8-HQMW
  3. AIDC-AI/ComfyUI-Copilot GitHub repository
  4. ComfyUI-Copilot issue #149 (disclosure)
  5. ComfyUI-Copilot PR #150 (proposed fix)
  6. ComfyUI-Copilot releases page
  7. ComfyUI-Copilot project site
  8. MITRE CWE-99: Improper Control of Resource Identifiers
05 · The Call

Final Verdict
= UNCHANGED to LOW (2.8/10)

Why this verdict

  • Authentication required (PR:L): The attacker must already hold a valid session on the Copilot backend, which by itself filters out the unauthenticated drive-by class.
  • High attack complexity (AC:H): Vendor and CVSS both call exploitation difficult — non-trivial payload shape, possibly state-dependent.
  • Impact capped at C:L / I:N / A:N: Best-case attacker outcome is reading workflow JSON or adjacent file content the Copilot process can already see. No RCE, no integrity, no DoS.
  • Role multiplier: low-value role only. ComfyUI-Copilot runs in the (a) low-value-role bucket — creator workstation or isolated GenAI sandbox. There is no (c) high-value-role deployment pattern: it is not on DCs, identity providers, hypervisors, backup, CA, EDR, or supply-chain registries. Floor stays at LOW.
  • Installed-base evidence: Shodan-visible ComfyUI footprint is a few thousand worldwide, and the Copilot custom node is an opt-in subset — well under 1% of enterprise estates have it at all, and effectively 0% of regulated/identity-tier hosts.
  • EPSS 0.00232 + no KEV + no observed exploitation: All three exploit-prediction signals align with the LOW bucket.

Why not higher?

Upgrading to MEDIUM would require either a credible mass-exploitation signal (none — EPSS bottom-quartile, no KEV, no campaigns) or a role-multiplier story where the affected component lands on a high-value asset (impossible — Copilot is a creator-tier plugin). The impact ceiling itself (C:L/I:N/A:N) caps the realistic damage well below what MEDIUM implies.

Why not lower?

We didn't push to IGNORE because a public PoC exists, no patched version has shipped yet (PR #150 unmerged), and the vulnerability is reachable over the network by any low-privileged user — so a multi-tenant Copilot deployment with sloppy auth scoping could genuinely leak another tenant's workflow. That keeps it in the tracked-backlog bucket, not the document-and-forget bucket.

06 · Verification

Crowdsourced verification payload.

Run on any host that may have ComfyUI-Copilot installed (developer workstation, GPU server, AI sandbox). Invoke as python check_cve_2026_13493.py /path/to/ComfyUI/custom_nodes — defaults to scanning the current directory if no path given. Needs only read access to the ComfyUI custom_nodes directory; no elevated privileges required.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# check_cve_2026_13493.py
# Detects vulnerable installs of AIDC-AI/ComfyUI-Copilot (<= 2.0.28).
# Exit codes: 0=PATCHED/NotInstalled, 1=VULNERABLE, 2=UNKNOWN

import os, re, sys, json
from pathlib import Path

VULN_MAX = (2, 0, 28)   # inclusive: every version <= 2.0.28 is affected

def parse_version(v):
    m = re.match(r"(\d+)\.(\d+)\.(\d+)", v.strip().lstrip("vV"))
    return tuple(int(x) for x in m.groups()) if m else None

def find_copilot_roots(base):
    roots = []
    for p in Path(base).rglob("ComfyUI-Copilot"):
        if p.is_dir():
            roots.append(p)
    return roots

def extract_version(root):
    # Try common locations in order.
    candidates = [
        root / "pyproject.toml",
        root / "setup.py",
        root / "package.json",
        root / "__init__.py",
        root / "VERSION",
    ]
    for c in candidates:
        if not c.exists():
            continue
        try:
            text = c.read_text(errors="ignore")
        except Exception:
            continue
        if c.name == "package.json":
            try:
                v = json.loads(text).get("version")
                if v: return v
            except Exception:
                pass
        m = re.search(r"version\s*=\s*[\"']([0-9]+\.[0-9]+\.[0-9]+)", text, re.I)
        if m: return m.group(1)
        m = re.search(r"__version__\s*=\s*[\"']([0-9]+\.[0-9]+\.[0-9]+)", text)
        if m: return m.group(1)
    return None

def main():
    base = sys.argv[1] if len(sys.argv) > 1 else "."
    if not Path(base).exists():
        print(f"UNKNOWN: path not found: {base}")
        return 2
    roots = find_copilot_roots(base)
    if not roots:
        print("PATCHED: ComfyUI-Copilot not installed under", base)
        return 0
    worst = 0
    for r in roots:
        v = extract_version(r)
        if not v:
            print(f"UNKNOWN: {r} — version not determinable")
            worst = max(worst, 2)
            continue
        parsed = parse_version(v)
        if parsed is None:
            print(f"UNKNOWN: {r} — version string {v!r} unparseable")
            worst = max(worst, 2)
            continue
        status = "VULNERABLE" if parsed <= VULN_MAX else "PATCHED"
        print(f"{status}: {r} (version {v})")
        if status == "VULNERABLE":
            worst = max(worst, 1)
    return worst

if __name__ == "__main__":
    sys.exit(main())