Files
Anso 966cf7255b fix(security): make ignored forwarded headers loud (#2069)
* fix(security): make ignored forwarded headers loud

Behind a reverse proxy, forwarding headers are accepted only from peers
listed in SENCHO_TRUSTED_PROXY_CIDRS. When the list is unset or invalid,
that failure was silent: client addresses, secure-cookie detection, SSO
callback URLs, Pilot enrollment URLs, and rate-limit keys all fell back
to the proxy, and an invalid list (for example a bare IP) was ignored
without a word.

Log the effective policy at boot, naming every rejected entry and the
reason. Warn once per untrusted peer when a request carries forwarding
headers the policy is ignoring, with the exact CIDR to set. Document the
behavior in the reverse-proxy and troubleshooting pages. The fail-closed
semantics of the allowlist are unchanged.

The login limiter test now drives the real createApp pipeline instead of
setting trust proxy by hand, which is what hid this regression.

* fix(security): keep forwarding headers out of the pilot tunnel

The tunnel bridge framed the hub's incoming request headers as-is, so a
reverse proxy in front of the hub had its X-Forwarded-* headers relayed
to the agent. The agent replays them to its loopback listener, which saw
them from 127.0.0.1 and warned about an untrusted proxy, suggesting the
operator trust loopback. Strip forwarding headers when framing http_req
and ws_open so the tunnel carries no unverifiable client address; the
hub's own pipeline has already applied its trusted-proxy policy to the
original request. Forwarded (RFC 7239) is stripped defensively.

Also narrow the reverse-proxy docs to the limiters that actually share a
bucket (sign-in, SSO, and other unauthenticated requests; signed-in
requests stay per user or per token), assert the boot log wiring, and
word the runtime warning as "add" when the list is configured, or point
at the rejected entries when it is invalid.

* docs(security): qualify trusted-proxy attribution and warning scope

QA follow-ups on the previous commit. The reverse-proxy paragraph now
says the proxy transport is the one where a remote can name the
operator's address if it trusts the forwarding instance; Pilot agents
receive tunneled requests without forwarding headers, so their local
audit trail records the tunnel ingress and the hub's audit log names the
operator. The runtime warning is documented as HTTP-only, since
WebSocket upgrades bypass Express middleware. The warning itself now
says "a reverse proxy or another Sencho instance" because a proxy-mode
remote's peer is the hub.
2026-10-03 10:35:43 -04:00
..