Skip to content

fix(security): harden CSRF with Content-Type gate and expand E2E coverage#2818

Merged
ltdrdata merged 1 commit intomanager-v4from
fix/csrf-post-conversion
Apr 21, 2026
Merged

fix(security): harden CSRF with Content-Type gate and expand E2E coverage#2818
ltdrdata merged 1 commit intomanager-v4from
fix/csrf-post-conversion

Conversation

@ltdrdata
Copy link
Copy Markdown
Member

@ltdrdata ltdrdata commented Apr 21, 2026

Summary

  • Defense-in-depth CSRF hardening: Content-Type gate on 16 no-body POST handlers (8 glob + 8 legacy) to block <form method=POST> that bypasses method-only gating. The three CORS-safelisted simple-form Content-Types (x-www-form-urlencoded, multipart/form-data, text/plain) are rejected with 400; any other Content-Type forces a CORS preflight the server does not answer.
  • comfyui_switch_version migrated to JSON body ({ver, client_id, ui_id}). db_mode/policy/update/channel_url_list split into GET(read) + POST(write, JSON body).
  • Security level tightening: do_fix 'high''high+' (align with SECURITY_MESSAGE_HIGH_P); comfyui_switch_version newly gated at 'high+'; three previously-ungated config setters (db_mode, policy/update, channel_url_list) now gated at 'middle'.
  • openapi.yaml fully resynchronized (27 paths, 30 operations, 3 dual-method splits). ComfyUISwitchVersionParams consolidated as a shared $ref component.
  • E2E infrastructure: 3 harness variants (start_comfyui_{legacy,permissive,strict}.sh), Playwright config + 6 legacy-UI spec files, pytest CSRF/secgate suites, 39-endpoint coverage matrix.
  • CHANGELOG.md (Keep a Changelog 1.1.0) added.

Breaking changes (migration notes in CHANGELOG.md)

  • Legacy per-op POST routes removed; callers already use POST /v2/manager/queue/batch:
    queue/install, queue/uninstall, queue/fix, queue/disable, queue/update, queue/reinstall, queue/abort_current.
  • GET /manager/notice (v1) removed; /v2/manager/notice retained.

Related

Test plan

  • ruff check comfyui_manager/ → All checks passed
  • python -m py_compile on all touched files → OK
  • pytest tests/ --ignore=tests/e2e --ignore=tests/playwright → 206 passed, 12 skipped (baseline preserved)
  • pytest --collect-only tests/e2e/test_e2e_csrf.py tests/e2e/test_e2e_csrf_legacy.py → 110 tests
  • In-process CSRF attack reproduction (fresh-eye review): 7/7 adversarial scenarios PASS
  • CORS Content-Type normalization probe (19 cases): no bypass path
  • python scripts/verify_audit_counts.py → PASS (122,0,0,1,123)
  • CI: Code Quality / Ruff / OpenAPI spec / E2E (ubuntu/macOS/Windows) — all green

Review summary

References

  • Reported-by: XlabAI Team of Tencent Xuanwu Lab
  • CVSS: 8.1 (AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H)

…rage

Defense-in-depth over GET→POST alone: reject the three CORS-safelisted
simple-form Content-Types (x-www-form-urlencoded, multipart/form-data,
text/plain) on 16 no-body POST handlers (glob + legacy) to block
<form method=POST> CSRF that bypasses method-only gating. Move
comfyui_switch_version to a JSON body so the preflight requirement applies.
Split db_mode/policy/update/channel_url_list into GET(read) + POST(write).
Tighten do_fix (high → high+) and gate three previously-ungated config
setters at middle. Resynchronize openapi.yaml (27 paths, 30 operations,
ComfyUISwitchVersionParams as a shared $ref component). Add E2E harness
variants, Playwright config, CSRF/secgate suites, 39-endpoint coverage,
and a CHANGELOG.

Breaking: legacy per-op POST routes (install/uninstall/fix/disable/update/
reinstall/abort_current) are removed; callers already use queue/batch.
Legacy /manager/notice (v1) is removed; /v2/manager/notice is retained.

Reported-by: XlabAI Team of Tencent Xuanwu Lab
CVSS: 8.1 (AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:H)
@ltdrdata ltdrdata force-pushed the fix/csrf-post-conversion branch from 9694fd7 to 4eb5727 Compare April 21, 2026 20:01
@ltdrdata ltdrdata merged commit 4410ebc into manager-v4 Apr 21, 2026
9 checks passed
@ltdrdata ltdrdata deleted the fix/csrf-post-conversion branch April 21, 2026 20:04
ltdrdata added a commit to Comfy-Org/ComfyUI_frontend that referenced this pull request Apr 22, 2026
Align with Comfy-Org/ComfyUI-Manager#2818 (CSRF Content-Type gate).
Convert START_QUEUE, UPDATE_ALL, UPDATE_COMFYUI, REBOOT to POST with
body=null and preserved query params where present. Request shape is
compatible with both the current GET backend and the upcoming
POST-only backend: body=null + axios default application/json header
is explicitly allowed by the backend's reject_simple_form_post gate
(only x-www-form-urlencoded, multipart/form-data, text/plain are
rejected).

Refs: Comfy-Org/ComfyUI-Manager#2818
ltdrdata added a commit to Comfy-Org/ComfyUI_frontend that referenced this pull request Apr 22, 2026
…gate

Align with Comfy-Org/ComfyUI-Manager#2818 (shipped in 4.2.0) and
Comfy-Org/ComfyUI-Manager#2820 (shipped in 4.2.1).

Service layer:
- Convert START_QUEUE, UPDATE_ALL, UPDATE_COMFYUI, REBOOT to POST with
  body=null and preserved query params. Request shape compatible with
  the reject_simple_form_post gate (body=null + axios default
  application/json header is allowed).

UI/state layer (useManagerState):
- Add ManagerUIState.INCOMPATIBLE triggered when the Manager backend
  does not advertise extension.manager.supports_csrf_post. Treated as
  "not installed" — Manager buttons hide via shouldShowManagerButtons.
- One-shot upgrade toast via watch(immediate:true) with a module-level
  guard; openManager() re-emits the toast on explicit user action.
- i18n (en/ko) for the upgrade-required notification.

Refs: Comfy-Org/ComfyUI-Manager#2818, Comfy-Org/ComfyUI-Manager#2820
ltdrdata added a commit that referenced this pull request Apr 22, 2026
This PR merges as the 4.2.1 release, so the [Unreleased] section
(PR #2818 CSRF hardening content) becomes part of 4.2.1. Consolidated
into a single [4.2.1] entry with Security/Changed/Added/Removed/Migration
notes; removed the now-empty [Unreleased] section and its compare link.
ltdrdata added a commit that referenced this pull request Apr 22, 2026
… feature flag

Expose CSRF-POST backend capability as a semantic contract via ComfyUI core's
feature_flags mechanism, so frontends (ComfyUI_frontend, extensions) can detect
it without parsing version strings. Manager versions prior to 4.2.1 do not set
the flag — clients observe its absence and should treat the backend as
"incompatible with POST-only state-mutation endpoints" and prompt the user to
upgrade.

Follow-up to #2818; no endpoint or security behavior change.

CHANGELOG: [Unreleased] folded into the 4.2.1 release entry (this PR ships as
4.2.1, so the PR #2818 CSRF hardening content belongs under the same release);
compare link anchored at v4.1b6 since no v4.2 tag will be created.
ltdrdata added a commit that referenced this pull request Apr 22, 2026
… feature flag

Lets clients detect CSRF-POST backend support via ComfyUI core's feature_flags
instead of parsing version strings. Absence of the flag indicates a Manager
version < 4.2.1 that is incompatible with POST-only state-mutation endpoints.

Follow-up to #2818; no endpoint or security behavior change.

CHANGELOG: fold [Unreleased] into the 4.2.1 entry (this PR ships as 4.2.1);
compare link anchored at v4.1b6 (no v4.2 tag planned).
ltdrdata added a commit that referenced this pull request Apr 22, 2026
… feature flag

Lets clients detect CSRF-POST backend support via ComfyUI core's feature_flags
instead of parsing version strings. Absence of the flag indicates a Manager
version < 4.2.1 that is incompatible with POST-only state-mutation endpoints.

Follow-up to #2818; no endpoint or security behavior change.
ltdrdata added a commit that referenced this pull request Apr 22, 2026
… feature flag (#2823)

Lets clients detect CSRF-POST backend support via ComfyUI core's feature_flags
instead of parsing version strings. Absence of the flag indicates a Manager
version < 4.2.1 that is incompatible with POST-only state-mutation endpoints.

Follow-up to #2818; no endpoint or security behavior change.
ltdrdata added a commit to Comfy-Org/ComfyUI_frontend that referenced this pull request Apr 22, 2026
Align with Comfy-Org/ComfyUI-Manager backend changes:
- #2818 (4.2.0): CSRF Content-Type gate + GET→POST migration for
  state-mutation endpoints.
- #2823 (4.2.1): register `extension.manager.supports_csrf_post`
  server feature flag so clients can detect POST-capable backends
  without version string parsing.

Service layer (comfyManagerService):
- Convert START_QUEUE, UPDATE_ALL, UPDATE_COMFYUI, REBOOT to POST
  with body=null and preserved query params. Backend's
  reject_simple_form_post gate allows body=null + axios default
  application/json header; only the three CORS simple-form types
  (x-www-form-urlencoded, multipart/form-data, text/plain) are
  rejected.

UI/state layer (useManagerState):
- Add ManagerUIState.INCOMPATIBLE — entered when the backend
  advertises supports_manager_v4 but not supports_csrf_post (old
  Manager that cannot handle the new POST endpoints). Manager UI
  is treated as "not installed": shouldShowManagerButtons returns
  false and consumers (TopMenuSection, MissingNodeCard,
  MissingPackGroupRow, TabErrors) hide their entry points without
  any call-site change.
- Graceful degraded mode while users remain on Manager <4.2.1:
  one-shot upgrade toast (warn, 15s) dispatched via
  watch(immediate:true) with a module-level guard that survives
  multiple composable instances; openManager() re-emits on explicit
  user action so stale shortcuts still surface guidance.
- i18n (en/ko) for the upgrade-required notification covering
  Desktop / standalone pip / Manager UI self-update paths.

Existing policies preserved:
- `--enable-manager` absent → DISABLED (unchanged).
- `--enable-manager-legacy-ui` → LEGACY_UI (unchanged).
- server feature flags not yet loaded (undefined) → NEW_UI
  transient fallback (unchanged).

Refs: Comfy-Org/ComfyUI-Manager#2818, Comfy-Org/ComfyUI-Manager#2823
ltdrdata added a commit to Comfy-Org/ComfyUI_frontend that referenced this pull request Apr 22, 2026
Align with Comfy-Org/ComfyUI-Manager backend changes:
- #2818 (4.2.0): CSRF Content-Type gate + GET→POST migration for
  state-mutation endpoints.
- #2823 (4.2.1): register `extension.manager.supports_csrf_post`
  server feature flag so clients can detect POST-capable backends
  without version string parsing.

Service layer (comfyManagerService):
- Convert START_QUEUE, UPDATE_ALL, UPDATE_COMFYUI, REBOOT to POST
  with body=null and preserved query params. Backend's
  reject_simple_form_post gate allows body=null + axios default
  application/json header; only the three CORS simple-form types
  (x-www-form-urlencoded, multipart/form-data, text/plain) are
  rejected.

UI/state layer (useManagerState):
- Add ManagerUIState.INCOMPATIBLE — entered when the backend
  advertises supports_manager_v4 but not supports_csrf_post (old
  Manager that cannot handle the new POST endpoints). Manager UI
  is treated as "not installed": shouldShowManagerButtons returns
  false and consumers (TopMenuSection, MissingNodeCard,
  MissingPackGroupRow, TabErrors) hide their entry points without
  any call-site change.
- Graceful degraded mode while users remain on Manager <4.2.1:
  one-shot upgrade toast (warn, 15s) dispatched via
  watch(immediate:true) with a module-level guard that survives
  multiple composable instances; openManager() re-emits on explicit
  user action so stale shortcuts still surface guidance.
- i18n (en/ko) for the upgrade-required notification covering
  Desktop / standalone pip / Manager UI self-update paths.

Existing policies preserved:
- `--enable-manager` absent → DISABLED (unchanged).
- `--enable-manager-legacy-ui` → LEGACY_UI (unchanged).
- server feature flags not yet loaded (undefined) → NEW_UI
  transient fallback (unchanged).

Refs: Comfy-Org/ComfyUI-Manager#2818, Comfy-Org/ComfyUI-Manager#2823
ltdrdata added a commit to Comfy-Org/ComfyUI_frontend that referenced this pull request Apr 23, 2026
Align with Comfy-Org/ComfyUI-Manager backend changes:
- #2818 (4.2.0): CSRF Content-Type gate + GET→POST migration for
  state-mutation endpoints.
- #2823 (4.2.1): register `extension.manager.supports_csrf_post`
  server feature flag so clients can detect POST-capable backends
  without version string parsing.

Service layer (comfyManagerService):
- Convert START_QUEUE, UPDATE_ALL, UPDATE_COMFYUI, REBOOT to POST
  with body=null and preserved query params. Backend's
  reject_simple_form_post gate allows body=null + axios default
  application/json header; only the three CORS simple-form types
  (x-www-form-urlencoded, multipart/form-data, text/plain) are
  rejected.

UI/state layer (useManagerState):
- Add ManagerUIState.INCOMPATIBLE — entered when the backend
  advertises supports_manager_v4 but not supports_csrf_post (old
  Manager that cannot handle the new POST endpoints). Manager UI
  is treated as "not installed": shouldShowManagerButtons returns
  false and consumers (TopMenuSection, MissingNodeCard,
  MissingPackGroupRow, TabErrors) hide their entry points without
  any call-site change.
- Graceful degraded mode while users remain on Manager <4.2.1:
  one-shot upgrade toast (warn, 15s) dispatched via
  watch(immediate:true) with a module-level guard that survives
  multiple composable instances; openManager() re-emits on explicit
  user action so stale shortcuts still surface guidance.
- i18n (en/ko) for the upgrade-required notification covering
  Desktop / standalone pip / Manager UI self-update paths.

Existing policies preserved:
- `--enable-manager` absent → DISABLED (unchanged).
- `--enable-manager-legacy-ui` → LEGACY_UI (unchanged).
- server feature flags not yet loaded (undefined) → NEW_UI
  transient fallback (unchanged).

Refs: Comfy-Org/ComfyUI-Manager#2818, Comfy-Org/ComfyUI-Manager#2823
ltdrdata added a commit to Comfy-Org/ComfyUI_frontend that referenced this pull request Apr 23, 2026
Align with Comfy-Org/ComfyUI-Manager backend changes:
- #2818 (4.2.0): CSRF Content-Type gate + GET→POST migration for
  state-mutation endpoints.
- #2823 (4.2.1): register `extension.manager.supports_csrf_post`
  server feature flag so clients can detect POST-capable backends
  without version string parsing.

Service layer (comfyManagerService):
- Convert START_QUEUE, UPDATE_ALL, UPDATE_COMFYUI, REBOOT to POST
  with body=null and preserved query params. Backend's
  reject_simple_form_post gate allows body=null + axios default
  application/json header; only the three CORS simple-form types
  (x-www-form-urlencoded, multipart/form-data, text/plain) are
  rejected.

UI/state layer (useManagerState):
- Add ManagerUIState.INCOMPATIBLE — entered when the backend
  advertises supports_manager_v4 but not supports_csrf_post (old
  Manager that cannot handle the new POST endpoints). Manager UI
  is treated as "not installed": shouldShowManagerButtons returns
  false and consumers (TopMenuSection, MissingNodeCard,
  MissingPackGroupRow, TabErrors) hide their entry points without
  any call-site change.
- Graceful degraded mode while users remain on Manager <4.2.1:
  one-shot upgrade toast (warn, 15s) dispatched via
  watch(immediate:true) with a module-level guard that survives
  multiple composable instances; openManager() re-emits on explicit
  user action so stale shortcuts still surface guidance.
- i18n (en/ko) for the upgrade-required notification covering
  Desktop / standalone pip / Manager UI self-update paths.

Existing policies preserved:
- `--enable-manager` absent → DISABLED (unchanged).
- `--enable-manager-legacy-ui` → LEGACY_UI (unchanged).
- server feature flags not yet loaded (undefined) → NEW_UI
  transient fallback (unchanged).

Refs: Comfy-Org/ComfyUI-Manager#2818, Comfy-Org/ComfyUI-Manager#2823
christian-byrne pushed a commit to Comfy-Org/ComfyUI_frontend that referenced this pull request Apr 23, 2026
## Summary

Align `comfyManagerService` and Manager UI state with CSRF hardening in
[Comfy-Org/ComfyUI-Manager#2818](Comfy-Org/ComfyUI-Manager#2818)
(4.2.0, Content-Type gate + GET→POST migration) and
[Comfy-Org/ComfyUI-Manager#2823](Comfy-Org/ComfyUI-Manager#2823)
(4.2.1, `extension.manager.supports_csrf_post` feature flag).

## Changes

- **Service layer**: Convert 4 state-mutation endpoints (`START_QUEUE`,
`UPDATE_ALL`, `UPDATE_COMFYUI`, `REBOOT`) from GET to POST. `body=null`
+ axios default `Content-Type: application/json` is allowed by the
backend's `reject_simple_form_post` gate (only the three CORS
simple-form types are rejected).
- **UI/state layer**: Add `ManagerUIState.INCOMPATIBLE` triggered when
the backend advertises `supports_manager_v4` but not
`supports_csrf_post`. Manager UI is treated as "not installed" — buttons
hide via `shouldShowManagerButtons` with zero call-site changes across
`TopMenuSection`, `MissingNodeCard`, `MissingPackGroupRow`, `TabErrors`.
- **Graceful degraded mode**: One-shot upgrade toast (warn, 15s)
dispatched via `watch(immediate:true)` with a module-level guard that
survives multiple composable instances. `openManager()` re-emits on
explicit user action so stale shortcuts still surface guidance. i18n
(en/ko) covering Desktop / standalone pip / Manager UI self-update
paths.
- **Breaking**: None. Existing policies preserved (`--enable-manager`
absent → `DISABLED`; `--enable-manager-legacy-ui` → `LEGACY_UI`; feature
flags not yet loaded → `NEW_UI` transient fallback).

## Review Focus

- Decision-tree ordering in `useManagerState.ts`: `supports_csrf_post`
check evaluates before `NEW_UI`/`LEGACY_UI` branches so stale Manager
backends never reach the enabled paths.
- Toast guard: module-level `incompatibleToastShown` survives multiple
composable instances (tests verify 3× `useManagerState()` = 1 toast
call).
- `generatedManagerTypes.ts` still declares the 4 endpoints as GET;
regeneration follows once Manager 4.2.1 OpenAPI is published. Runtime is
unaffected since axios operates on the route string.

## References

-
[Comfy-Org/ComfyUI-Manager#2818](Comfy-Org/ComfyUI-Manager#2818)
— CSRF Content-Type gate + GET→POST migration (4.2.0)
-
[Comfy-Org/ComfyUI-Manager#2823](Comfy-Org/ComfyUI-Manager#2823)
— `supports_csrf_post` feature flag (4.2.1)
- [comfyui-manager 4.2.1 on
PyPI](https://pypi.org/project/comfyui-manager/4.2.1) — release package
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant