From 873b00e070f832eb0162e01f0d98cd0a75c98050 Mon Sep 17 00:00:00 2001 From: Jage9 Date: Mon, 2 Mar 2026 00:41:58 -0500 Subject: [PATCH] Harden forwarded IP parsing for auth throttling --- server/app/server.py | 5 ++++- server/tests/test_server_message_handling.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/server/app/server.py b/server/app/server.py index 7c297a9..49918fa 100644 --- a/server/app/server.py +++ b/server/app/server.py @@ -481,7 +481,10 @@ class SignalingServer: forwarded = str(headers.get("X-Forwarded-For", "")).strip() if not forwarded: return peer_ip - for candidate in forwarded.split(","): + # In common reverse-proxy chains, the trusted proxy appends the immediate + # client IP to the end of X-Forwarded-For. Read right-to-left so a + # client-supplied left-side value can't spoof throttling/audit identity. + for candidate in reversed(forwarded.split(",")): parsed = SignalingServer._normalized_ip(candidate) if parsed: return parsed diff --git a/server/tests/test_server_message_handling.py b/server/tests/test_server_message_handling.py index e8136ad..52633c1 100644 --- a/server/tests/test_server_message_handling.py +++ b/server/tests/test_server_message_handling.py @@ -30,7 +30,7 @@ def test_client_ip_prefers_forwarded_for_from_loopback_proxy() -> None: ServerConnection, SimpleNamespace( remote_address=("127.0.0.1", 12345), - request=SimpleNamespace(headers={"X-Forwarded-For": "198.51.100.25, 127.0.0.1"}), + request=SimpleNamespace(headers={"X-Forwarded-For": "203.0.113.10, 198.51.100.25"}), ), ) client = ClientConnection(websocket=ws, id="u1", nickname="tester")