Severity: π‘ Medium (security; insecure bind allowed silently)
config.py:160β164 defaults serve.bind to 127.0.0.1. But there is no guard that refuses a non-loopback bind when auth_token is unset. A user who sets serve.bind: 0.0.0.0 and leaves auth_token: null exposes the Perseus serve endpoint on all interfaces. The Host-header check is some protection against DNS rebinding but is not hardened access control.
Suggested fix
In cmd_serve (or wherever HTTPServer is created):
host = _serve_bind_host(cfg)
token = _serve_auth_token(cfg)
if not _serve_is_loopback(host) and not token:
if not cfg.get("serve", {}).get("allow_insecure_remote", False):
raise SystemExit(
f"Refusing to bind to {host} without auth_token. "
f"Set serve.auth_token, or serve.allow_insecure_remote: true to override."
)
Acceptance criteria
- Test:
bind=0.0.0.0, auth_token=None, allow_insecure_remote=False β SystemExit.
- Test: same with
allow_insecure_remote=True β starts (with stderr warning).
- Test: same with
auth_token set β starts normally.
Severity: π‘ Medium (security; insecure bind allowed silently)
config.py:160β164defaultsserve.bindto127.0.0.1. But there is no guard that refuses a non-loopback bind whenauth_tokenis unset. A user who setsserve.bind: 0.0.0.0and leavesauth_token: nullexposes the Perseus serve endpoint on all interfaces. The Host-header check is some protection against DNS rebinding but is not hardened access control.Suggested fix
In
cmd_serve(or wherever HTTPServer is created):Acceptance criteria
bind=0.0.0.0,auth_token=None,allow_insecure_remote=Falseβ SystemExit.allow_insecure_remote=Trueβ starts (with stderr warning).auth_tokenset β starts normally.