Comfy-Org / Comfy-Org/ComfyUI

origin_only_middleware returns 403 for any Sec-Fetch-Site: cross-site request, breaking reverse proxies with auth on a separate domain (Cloudflare Access, oauth2-proxy, Authelia)

Open Beginner friendly
#16,203 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
133k
Forks
15.7k
Avg merge
1d 7h
Merged PRs (30d)
158

Description

# `origin_only_middleware` returns 403 for any `Sec-Fetch-Site: cross-site` request, breaking reverse proxies with auth on a separate domain (e.g. Cloudflare Access, oauth2-proxy, Authelia)

### Expected Behavior

Loading the ComfyUI web UI through a reverse proxy that performs authentication on a different hostname (Cloudflare Access, oauth2-proxy, Authelia, Authentik, etc.) should work. After the identity provider redirects the browser back to the ComfyUI hostname, the page should load.

### Actual Behavior

The first navigation to ComfyUI immediately after an external login redirect returns a bare **HTTP 403** (empty body, rendered by the browser as a generic "HTTP ERROR 403" page).

`create_origin_only_middleware()` in `server.py` rejects **any** request whose `Sec-Fetch-Site` header is `cross-site`:

```python
async def origin_only_middleware(request: web.Request, handler):
if 'Sec-Fetch-Site' in request.headers:
sec_fetch_site = request.headers['Sec-Fetch-Site']
if sec_fetch_site == 'cross-site':
return web.Response(status=403)
```

When an auth proxy on `auth.example.com` finishes login and 302-redirects the browser to `comfyui.example.com`, that top-level navigation carries `Sec-Fetch-Site: cross-site`. The middleware returns 403 before the request reaches any handler.

Notable details:

- The check is **not** limited to loopback hosts, unlike the `Host`/`Origin` comparison immediately below it (which is explicitly gated on `is_loopback(...)`). A cross-site *navigation* to a public, properly-authenticated deployment is not the threat that block comment describes (a random site POSTing to `127.0.0.1`).
- Pressing **reload** after the 403 works: the reload sends `Sec-Fetch-Site: same-origin` and the page loads normally. So the deployment is otherwise fully functional — only the post-login landing request is blocked.
- The 403 has an empty body, so users just see the browser's generic error page with no indication of the cause.
- This worked on 0.34.0-era builds and started failing after updating (the `Sec-Fetch-Site` block is newer than the loopback `Host`/`Origin` check).

### Steps to Reproduce

1. Run ComfyUI without `--enable-cors-header` (so `origin_only_middleware` is active).
2. Put it behind any auth proxy whose login page is on a different hostname (Cloudflare Access is the easiest repro).
3. From a fresh browser session, open the ComfyUI URL, complete the login on the IdP domain.
4. Get redirected back to the ComfyUI URL → **403**.
5. Press F5 → page loads.

Equivalent one-liner against the origin:

```bash
# 403
curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: comfyui.example.com' \
-H 'Origin: https://auth.example.com' -H 'Sec-Fetch-Site: cross-site' http://127.0.0.1:8188/

# 200
curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: comfyui.example.com' \
-H 'Sec-Fetch-Site: same-origin' http://127.0.0.1:8188/
```

### Suggested fix

Gate the `Sec-Fetch-Site` rejection on the same `is_loopback(host)` condition already used for the `Host`/`Origin` check just below it, so it only defends the `127.0.0.1` scenario the comment describes and does not break authenticated remote deployments. Alternatively, allow `cross-site` for top-level navigations (`Sec-Fetch-Mode: navigate` + `Sec-Fetch-Dest: document`), which is the case that matters for an IdP redirect, while still blocking `cross-site` requests to the API.

### Current workarounds

- `--enable-cors-header` (replaces `origin_only_middleware` with `cors_middleware`, which has no such check).
- A reverse-proxy / edge rule that strips the `Sec-Fetch-Site` request header for the ComfyUI hostname.
- Reload the page after the 403.

### Debug Logs

```
# server.py, create_origin_only_middleware — the offending block returns status=403 with no body,
# so nothing is logged. The warning log a few lines down (non-matching host/origin) is NOT hit.
```

### Other

Version: `master` (checked at commit ea33b15, 2026-09-07); also present at 82f839f. Python 3.12, ComfyUI run with `--listen 0.0.0.0 --port 8188` behind cloudflared + Cloudflare Access.

Contributor guide

Open the contributing guide

Research direction

Start in server.py at create_origin_only_middleware and reproduce the two curl requests from the issue. Check the existing is_loopback(host) guard and the Sec-Fetch-Site rejection together. Done means authenticated cross-site top-level navigation reaches the ComfyUI UI while the intended loopback protection remains effective.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend, security
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.