Files
magpie/docs
yetone c431225a08 gateway: a browser that reaches loopback under a web site's name (DNS rebinding) is refused unless it sends an enabled gateway key
What changed
- lanGuard refuses (403) a loopback request that carries a browser's
  marks (Origin, Sec-Fetch-Site/Mode, a Mozilla/ user agent) when its Host
  isn't this computer's: an IP, localhost, *.localhost, a container
  runtime's name for the host (host.docker.internal and kin),
  MAGPIE_PUBLIC_URL's or MAGPIE_ADDR's host, or the machine's own name.
  An enabled gateway key still lets it in.
- Why: a page whose DNS answers 127.0.0.1 after it loads is same-origin
  with the gateway. Its GET sends no Origin and its POST one equal to the
  Host, so corsGuard's foreignPage let it by, and on loopback no key is
  asked. The nightly security review reproduced it on origin/main: Host
  and Origin rebind.attacker.example:3425 from 127.0.0.1 got 200 on
  GET /v1/models, POST /v1/chat/completions (spends subscriptions) and
  GET /v1/magpie/quotas (account names, balances). The subsystem doc
  listed it as a known gap.
- Agents send none of a browser's marks and pass under any name; browsers
  and webviews calling localhost or an IP are unchanged.
- Tests: TestCORSKeyThroughTheServer and the Omarchy test now set a real
  Host (httptest's default is example.com). TestForeignPagesRefused's
  "own origin behind a port-443 name" row from loopback with no forwarding
  header now sends a key: without one it is the rebound page.
- docs/subsystems/gateway-routing.md describes the check in place of the gap.

Ran
- TestReboundPageRefused: fails on origin/main ("a rebound page's GET:
  200"), passes with the change.
- go test -count=1 ./internal/gateway/ ./internal/gui/ ./internal/access/
  (macOS, go1.27): ok. gofmt -l clean; GOOS=linux and GOOS=windows go vet
  ./internal/gateway/ clean.

Not tried: a real browser against a real rebinding DNS name.
2026-10-10 14:21:23 +08:00
..