Skip to content

fix(security): tolerate Chromium stripping port from Origin header - #544

Open
LCZcoding wants to merge 1 commit into
agegr:mainfrom
LCZcoding:fix/chromium-origin-port-stripping
Open

fix(security): tolerate Chromium stripping port from Origin header#544
LCZcoding wants to merge 1 commit into
agegr:mainfrom
LCZcoding:fix/chromium-origin-port-stripping

Conversation

@LCZcoding

Copy link
Copy Markdown

Summary

isApiRequestOriginAllowed (lib/request-security.ts) rejects all /api/*
requests with 403 on Chromium 150+, because Chrome now strips the port from
the Origin header for same-origin requests on non-default ports, and the
canonical-origin comparison (which includes the port) no longer matches.

pi-web defaults to port 30141, so every fresh install using a modern
Chromium-based browser is affected: the UI shows Error: HTTP 403, the
session sidebar appears empty, and the model config panel cannot load.

Fixes #542

Repro

  1. npm install && npm run dev on a fresh checkout
  2. Open http://127.0.0.1:30141 in Chrome 150+
  3. DevTools → Network → any /api/* request → status 403,
    response {"error":"Untrusted API request"}
  4. Request headers show Origin: http://127.0.0.1 (no port) vs
    Host: 127.0.0.1:30141

Fix

Compare Origin hostnames instead of full canonical origins. The Host
header is already validated by isApiRequestHostAllowed, so port
differences carry no trust signal — only hostname equality does.

Add originHostname() helper and switch isApiRequestOriginAllowed
to use hostname comparison.

Security

The Host allowlist, sec-fetch-site, and same-origin checks still
block DNS rebinding, cross-site fetches, opaque iframes, and cross
loopback-name origins (covered by new regression tests). The only
loosening is accepting same-hostname / different-port Origin headers,
which is the intended Chromium behavior.

Tests

  • New: allows same-origin requests when Chromium strips the port from Origin
    (covers loopback IP, LAN IP, loopback name)
  • New: still rejects when Origin hostname differs from Host even with port stripped
    (covers cross-loopback-name and DNS rebind)

Existing tests continue to pass.

Chromium 150+ omits the port from the Origin header for same-origin requests on non-default ports. The previous canonical-origin comparison (includes port) therefore rejected every legitimate pi-web API call, producing 'Error: HTTP 403' on the UI and an empty session sidebar.

Compare origin hostnames only; the Host header is the authoritative source for where the request actually went, and the host allowlist still rejects DNS-rebinding and cross-loopback-name origins.

Add tests covering loopback IP, LAN IP, and loopback name with the port stripped, plus regression tests for cross-name and DNS-rebind attacks.
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.

Bug: All API requests return 403 on Chromium 150+ browsers (PR #496 has been submitted)

1 participant