The client address taken from X-Forwarded-For is the first entry, which the client itself can set #181

Closed
opened 2026-10-01 21:43:12 +02:00 by clawbot · 1 comment
Collaborator

Found while implementing #101 (#180).

realIP in internal/middleware/middleware.go reads X-Forwarded-For only when the direct peer is a trusted proxy, but then takes the first entry. A proxy that appends to an X-Forwarded-For the client sent leaves the client's own value first, so the client chooses the address dnswatcher logs and, once #180 lands, the address its /metrics rate limit counts against: a client can escape the limit by sending a different value each time.

Definition of done

  • From X-Forwarded-For, the client address is the rightmost entry that is not a trusted proxy, walking from the right, using the existing trusted-proxy check (no second list). If every entry is a trusted proxy, the leftmost is used.
  • X-Real-IP handling is unchanged.
  • Tests: a client-sent first entry followed by the real client address added by a trusted proxy gives the real client address; a chain of several trusted proxies; the untrusted-peer case still ignores both headers. The tests fail on the old code.
  • Sequencing: after #180, which uses realIP for the rate limit and changes the same file.

Model: opus-5-5

Found while implementing https://git.eeqj.de/sneak/dnswatcher/issues/101 (https://git.eeqj.de/sneak/dnswatcher/pulls/180). `realIP` in `internal/middleware/middleware.go` reads `X-Forwarded-For` only when the direct peer is a trusted proxy, but then takes the first entry. A proxy that appends to an `X-Forwarded-For` the client sent leaves the client's own value first, so the client chooses the address dnswatcher logs and, once https://git.eeqj.de/sneak/dnswatcher/pulls/180 lands, the address its `/metrics` rate limit counts against: a client can escape the limit by sending a different value each time. ## Definition of done - From `X-Forwarded-For`, the client address is the rightmost entry that is not a trusted proxy, walking from the right, using the existing trusted-proxy check (no second list). If every entry is a trusted proxy, the leftmost is used. - `X-Real-IP` handling is unchanged. - Tests: a client-sent first entry followed by the real client address added by a trusted proxy gives the real client address; a chain of several trusted proxies; the untrusted-peer case still ignores both headers. The tests fail on the old code. - Sequencing: after https://git.eeqj.de/sneak/dnswatcher/pulls/180, which uses `realIP` for the rate limit and changes the same file. Model: opus-5-5
clawbot added this to the 1.0 milestone 2026-10-01 21:43:12 +02:00
Author
Collaborator

Implemented in #183: the client address is now the rightmost X-Forwarded-For entry that is not a trusted proxy, with all header lines read as one list; X-Real-IP is unchanged.

Model: opus-5-5

Implemented in https://git.eeqj.de/sneak/dnswatcher/pulls/183: the client address is now the rightmost `X-Forwarded-For` entry that is not a trusted proxy, with all header lines read as one list; `X-Real-IP` is unchanged. Model: opus-5-5
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/dnswatcher#181