Files
webhooker/internal
sneak b37ebeacad
All checks were successful
check / check (push) Successful in 2m46s
Gate forwarded-header trust behind trusted-proxy config (closes #88)
Every rate limiter keyed on httprate.KeyByRealIP, which believes
True-Client-IP, X-Real-IP and the first X-Forwarded-For entry from
any peer. A client could therefore mint a fresh bucket per request
by rotating a spoofed header, or drain another client's bucket by
claiming its address, which left the receiver, login and password
change limits with no value against a deliberate attacker.

The receiver, login and password change limiters now share one key
function: the connection's own address, unless the direct peer is
inside a network listed in the new TRUSTED_PROXIES CIDR list, in
which case the forwarded client address is used. The list is empty
by default, so nothing is trusted until an operator names their
proxy; a set-but-unparseable value aborts startup, matching the
handling of the other parsed variables.

X-Forwarded-For is the only forwarded header read, from any peer.
Reverse proxies append to it but pass other client headers through
verbatim, so believing a single-valued X-Real-IP or True-Client-IP
would hand a client behind the trusted proxy a fresh bucket per
request - the same bypass, inside the deployment TRUSTED_PROXIES
exists to serve. Within a trusted request the chain is walked right
to left, since the rightmost entry is the one the nearest proxy
appended, and the first hop that is not itself a trusted proxy is
taken as the client. A hop that is not a bare address - ip:port, a
bracketed IPv6 literal, the token unknown - ends the walk and the
peer address is used, rather than continuing left into entries the
client controls.

Trusted-proxy prefixes written in IPv4-mapped form are unmapped at
parse time, since peer addresses are unmapped before matching and
such a prefix would otherwise silently never match.

Also folds in two cleanups from the same review: the 429 responder
shared by all three limiters is extracted, and the
RECEIVER_RATE_LIMIT error-path tests now assert that the failure
names the variable and wraps ErrNonPositiveValue rather than only
that some error occurred.
2026-08-11 13:44:12 +00:00
..