You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Enforce localhost-only binding: refuse HOST=0.0.0.0 without an explicit opt-in #1795
The web server (both the prod backend clients/web/server/web-server-config.ts and the dev Vite server clients/web/vite.config.ts) passes the HOST env var straight through to its bind call with no validation. Setting HOST=0.0.0.0 (or ::, or empty) binds every network interface, exposing the Inspector's backend — which can spawn local processes and connect to MCP servers on the user's behalf — to the entire local network. That is precisely the surface DNS-rebinding attacks target.
The project's stated intent (specification/v2_scope.md: "Bind to localhost by default … never 0.0.0.0") was only a design note; nothing enforced it.
Proposal
Enshrine the localhost-only default in code, via a single shared guard used by both bind points:
Refuse an all-interfaces host (0.0.0.0 / :: / empty) by default, exiting with an actionable error.
Allow it only when DANGEROUSLY_BIND_ALL_INTERFACES=true is explicitly set (same DANGEROUSLY_* opt-in pattern as DANGEROUSLY_OMIT_AUTH).
The published Docker image is the sanctioned exception (a container must bind 0.0.0.0 to be reachable through -p), so its Dockerfile sets the flag.
Related fix folded into the same PR
Investigation started from a real bug: connecting to a plain stdio server (everything-server) failed with Remote connect failed (403): Invalid origin … DNS rebinding. Root cause: the dev server binds IPv6 loopback [::1], the browser lands on http://[::1]:6274, but the default allowedOrigins was the single literal string http://localhost:6274, so the origin guard 403'd the connect. The same PR expands the default loopback allowedOrigins to all three interchangeable forms (localhost, 127.0.0.1, [::1]) for the port.
Activity
docs(web): add 'Hosting on a network' note — specific-IP bind + ALLOW…
review: harden bind guard + IPv6 loopback consistency across origin/C…
review: round-2 fixes — gate plugin config eval, share host formatter…
review: round-3 fixes — close IPv6 wildcard bypass, default-port orig…
review: round-4 fixes — zone-index guard crash, CSP header hardening,…
review: round-5 fixes — wildcard allow-list, IPv6-in-CSP reality, URL…
review: round-6 fixes — empty-ALLOWED_ORIGINS fail-open, 0.0.0.0 is a…
review: round-7 fixes — canonical wildcard origins, sandbox URL, dedup (
review: round-8 fixes — normalize ALLOWED_ORIGINS, reject unusable CL…
review: round-9 fixes — reject scheme-less ALLOWED_ORIGINS, CLIENT_PO…
review: round-10 fixes — canonicalize the bind host on all origin-lis…
review: round-11 polish — verify --dev allowedHosts, dedupe port vali…
7 remaining items
review: round-19 fix — close the IDNA/fullwidth wildcard bypass in th…
review: round-20 fixes — untrack stray tsbuildinfo, self-explaining g…
review: round-21 — guard the CLI OAuth callback bind (AF1), message +…
review: round-22 — OAuth callback loopback-only + bracket fixes (#1795)
review: round-23 nits — bound isLoopbackHost octets, accept trailing-…
review: round-24 — OAuth guard error is a usage error, not auth_requi…
review: round-25 — preserve CLI exit codes/envelope through the launc…
review: round-26 nits — stale-build guard, non-1 exit smoke, DEBUG=0,…
review: round-27 nits — smoke env-pin + docblock, comments (#1795)
review: round-28 — correct dead-cover comments, ALLOWED_ORIGINS-repla…
review: round-29 — TUI smoke env-pin + root README ALLOWED_ORIGINS re…
feat(web): enforce localhost-only binding; expand loopback origin all…
cliffhall commentedon Jul 27, 2026
Merged via #1796 (squash
cea22d86). Auto-close doesn't fire on v2/main, so closing manually per AGENTS.md.