Commit graph

1 commit

Author SHA1 Message Date
chopratejas
665c0823d9 fix(proxy): F4 — trust X-Forwarded-* only behind allow-listed gateway
The proxy previously had no spoofing defence on `X-Forwarded-*`
headers. Any client could forge `X-Forwarded-For`, `-Proto`, or
`-Host` and rotate rate-limit buckets / poison logs / mis-attribute
auth. F4 adds an explicit gateway-allowlist gate.

* New `headroom/proxy/forwarded_headers.py` module:
  - `resolve_client_ip(request)` — IP for log/auth/rate-limit.
  - `trusted_forwarded_headers(request)` — sanitised `{for,proto,host}`
    dict (empty strings when the gate fails).
  - Configured by `HEADROOM_PROXY_TRUSTED_GATEWAY_CIDRS`
    (comma-separated CIDRs). Empty/unset = strict-secure default.
  - Malformed CIDR raises `ValueError` (loud, no silent skip).
  - Every spoof rejection emits `forwarded_headers_rejected` log
    event with `peer_ip` + the three header values.
  - Result cached on `request.state.{client_ip,forwarded}` so the
    helpers run once per request.

* Anthropic handler now keys the rate-limit bucket on the gated IP.

* 36 tests cover: default-strict / allow-listed peer / non-allow-listed
  peer (with log assertion) / IPv6 / IPv4-mapped IPv6 / multi-CIDR /
  whitespace tolerance / malformed CIDR loud-fail / empty headers /
  caching / FastAPI integration.
2026-05-06 14:37:09 -07:00