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)
- 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
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