ComfyUI-Manager/CHANGELOG.md
Dr.Lt.Data fca7ef149d
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
feat(security): dedicated install flags decouple git_url/pip install from security_level (#2962)
* feat(security): dedicated install flags decouple git_url/pip from security_level

Install via git URL and pip install are no longer gated by
security_level. Each surface gets a dedicated config.ini flag —
allow_git_url_install / allow_pip_install (both default false, secure
by default) — that fully REPLACES the security-level term for these two
features. The network-position invariant is retained: a non-local
listener stays denied regardless of the flags unless
network_mode = personal_cloud.

- New pure predicate is_dedicated_install_allowed() in
  common/manager_security (no config access; callers resolve config)
- Legacy endpoints /v2/customnode/install/git_url and .../pip switch
  from is_allowed_security_level('high+') to the flag gate; batch
  installs of unknown git URLs likewise (middle+ entry gate unchanged,
  unknown-pip 'block' stays unconditional; response shapes preserved)
- Config readers/writers (glob + legacy) parse and persist the flags;
  denial logs and frontend 403 messages name the responsible flag and
  note the non-local-listener requirement (network_mode=personal_cloud)
- No auto-seed from security_level — users previously on weak/normal-
  must opt in explicitly (see CHANGELOG migration notes; README
  documents the new contract)
- Update the pre-existing permissive E2E harness
  (start_comfyui_permissive.sh + test_e2e_legacy_real_ops.py) to the
  new contract: it now also sets allow_git_url_install /
  allow_pip_install = true, since security_level = normal- alone no
  longer opens the git_url/pip endpoints

Tests: predicate truth table proving security_level independence in
both directions, dual-reader config contract, security-level-matrix
freeze guards, legacy gate regression guards (121 unit), plus 22
real-server E2E tests incl. URL-form pip install with self-clean.

* test(e2e): fix fresh-env failures in customnode_info and git_clone harnesses

Two pre-existing harness defects that fail deterministically on a fresh
E2E environment (unrelated to the dedicated-install-flags change):

- test_e2e_customnode_info: TestInstalledPacks asserted the seed pack
  ComfyUI_SigmoidOffsetScheduler is installed, but nothing seeded it —
  the installing module (test_e2e_endpoint) runs alphabetically later
  and uninstalls it at the end. Add a module-scoped autouse fixture
  that installs the pack via cm-cli BEFORE the server starts (the
  imported-mode test asserts against the startup-frozen snapshot, so
  API-based seeding after boot cannot work) and removes it on teardown
  only if the fixture installed it.
- test_e2e_git_clone: _ensure_cache ran cm-cli update-cache with a
  120s timeout; the full DB download routinely exceeds that on slow
  links, erroring the whole module at setup. Raise to 600s.

Verified from a fresh state (seed pack absent): both modules pass
(13 tests, incl. previously-failing TestInstalledPacks 2 and
TestNightlyInstallCycle 3).
2026-06-11 01:44:12 +09:00

8.2 KiB

Changelog

All notable changes to ComfyUI-Manager are documented in this file.

The format is based on Keep a Changelog 1.1.0, and this project adheres to Semantic Versioning 2.0.0.

[Unreleased]

Security

  • Dedicated install flags decouple git-URL / pip installs from security_level: POST /v2/customnode/install/git_url and POST /v2/customnode/install/pip (and the batch install path for git URLs not in the custom-node DB) are now gated by two new config.ini [default] flags — allow_git_url_install and allow_pip_install — instead of security_level. Both default to false (secure by default), and a non-loopback listener stays denied unless network_mode = personal_cloud (the existing network-position invariant is retained — the flags never widen exposure beyond what was possible before). security_level no longer has any effect on these two endpoints, in either direction. The unknown-pip-package block in batch installs remains unconditional. Activation requires a restart (no hot reload).

Migration notes

  • Users running security_level = weak or normal-: these environments could previously use the git-URL / pip install endpoints; after upgrading they are denied (HTTP 403) until you explicitly opt in by setting allow_git_url_install = true and/or allow_pip_install = true in the [default] section of config.ini. The flags are NOT auto-seeded from your security_level — explicit opt-in is intentional.

4.2.1 - 2026-04-22

Security-hardening release. Contains breaking-ish API changes for state-mutating endpoints. See Migration notes below before upgrading programmatic clients.

Security

  • CSRF Content-Type gate: 18 state-mutation POST handlers (9 in glob, 9 in legacy) now reject the three CORS "simple request" Content-Types (application/x-www-form-urlencoded, multipart/form-data, text/plain). This closes the residual <form method="POST"> bypass route that remained after the GET→POST transition. Legitimate clients using application/json (or no body) are unaffected.
  • do_fix security level raised from high to high+: aligns the enforcement gate (is_allowed_security_level) with the log text emitted by SECURITY_MESSAGE_HIGH_P. Both glob/manager_server.py and legacy/manager_server.py updated in lockstep. Environments running at security_level = high can no longer fix a nodepack — use security_level = normal or lower.
  • Config setters now gated at middle security level: POST /v2/manager/db_mode, POST /v2/manager/policy/update, and POST /v2/manager/channel_url_list now check is_allowed_security_level('middle') before mutating configuration (both glob and legacy). Closes a pre-existing gap where the write path was reachable at any security level. Reads (GET) remain unrestricted.

Changed

  • State-changing endpoints converted from GET to POST (CSRF hardening): /v2/manager/queue/{update_all, reset, start, update_comfyui}, /v2/snapshot/{remove, restore, save}, /v2/comfyui_manager/comfyui_switch_version, /v2/manager/reboot. Query-string parameters are preserved where they existed; only the HTTP method changes.
  • POST /v2/comfyui_manager/comfyui_switch_version parameters moved from query string to JSON body (REST idiom + body-reading CSRF posture): The handler now consumes application/json with the body shape {"ver": "...", "client_id": "...", "ui_id": "..."} instead of reading ?ver=...&client_id=...&ui_id=... from the URL. Because body-reading handlers are already covered by the CORS-preflight mechanism for cross-origin protection, the Content-Type rejection gate introduced for the other state-mutation endpoints is intentionally NOT applied here (see comfyui_manager/common/manager_security.py module docstring). The first-party JS client in comfyui_manager/js/comfyui-manager.js was updated in the same change; third-party callers must migrate.
  • Config endpoints split into GET (read) + POST (write): /v2/manager/{db_mode, policy/update, channel_url_list}. GET returns the current value; POST accepts a JSON body {"value": "..."}. The prior single-method form that accepted a ?value=... query parameter on either verb is retired.
  • openapi.yaml fully resynchronized with the server: HTTP methods, the dual-method splits above, request-body schemas for the new POST setters, and the TaskHistoryItem.params field now match manager_server.py.
  • Legacy restart(self)restart(request): parameter name corrected. No behavioral change.

Added

  • Server-push feature flag extension.manager.supports_csrf_post registered at startup, allowing ComfyUI-frontend (and other clients) to detect CSRF-POST backend support as a semantic capability contract, without relying on version string parsing. Manager versions prior to 4.2.1 do not set the flag — clients should treat its absence as 'incompatible with POST-only state-mutation endpoints'.
  • E2E test harness variants for security-level and legacy-mode scenarios: tests/e2e/scripts/start_comfyui_legacy.sh, tests/e2e/scripts/start_comfyui_permissive.sh, tests/e2e/scripts/start_comfyui_strict.sh. See docs/guide/GUIDE_E2E_TEST.md for usage.
  • COMFYUI_MANAGER_SKIP_MANAGER_REQUIREMENTS environment variable: when set, skips the manager_requirements.txt reinstall path. Intended for E2E environments where those dependencies are provisioned separately.
  • TaskHistoryItem.params field (Pydantic + openapi.yaml): mirrors QueueTaskItem.params so that task history retains the original request payload (nullable when unavailable).
  • Automated endpoint coverage — pytest E2E + Playwright specs covering all 39 unique (method, path) endpoints across glob and legacy. Coverage is tracked in reports/api-coverage-matrix.md and reports/e2e_test_coverage.md.

Removed

  • Legacy per-operation POST routes consolidated into POST /v2/manager/queue/batch: /v2/manager/queue/{install, uninstall, update, fix, disable, reinstall, abort_current}. The first-party JS client already uses queue/batch; only third-party scripts that call the per-operation routes directly are affected.
  • GET /manager/notice (v1, pip-install redirect banner). GET /v2/manager/notice remains available.

Migration notes

  • Third-party clients calling POST /v2/manager/queue/install (and the other per-operation queue routes) must switch to POST /v2/manager/queue/batch with a body such as {"install": [{id, ver, ...}], "batch_id": "..."}. See reports/endpoint_scenarios.md for the full payload shape.
  • Programmatic clients that posted to the CSRF-hardened endpoints with application/x-www-form-urlencoded, multipart/form-data, or text/plain must switch to application/json (or omit the body entirely when the endpoint takes its parameters from the query string).
  • Clients that called any of the methods listed under Changed → State-changing endpoints with GET must switch to POST. Query parameters remain valid.
  • Clients that wrote configuration via GET /v2/manager/{db_mode, policy/update, channel_url_list}?value=... must switch to POST with JSON body {"value": "..."}.
  • Third-party scripts calling POST /v2/comfyui_manager/comfyui_switch_version?ver=...&client_id=...&ui_id=... must switch to POST with Content-Type: application/json and body {"ver": "...", "client_id": "...", "ui_id": "..."}. The query-string form no longer works.
  • Environments running at security_level = high can no longer run do_fix. Either lower the security level (normal, normal-, or weak as appropriate) or skip the fix operation.
  • Environments running at security_level = high can no longer mutate db_mode, policy/update, or channel_url_list via POST (returns 403). Lower the security level to normal or below to change configuration, or perform the change from a trusted entry point. Read access via GET is unaffected.