summaryrefslogtreecommitdiff
path: root/searx/botdetection/trusted_proxies.py
diff options
context:
space:
mode:
authorIvan Gabaldon <igabaldon@inetol.net>2026-08-20 18:06:24 +0200
committerGitHub <noreply@github.com>2026-08-20 18:06:24 +0200
commit487d7a96e0f1b74c65c4e22e366dce12a96e5ac2 (patch)
tree3b05c92cd3ee473b1e37001714b83ba9a600b474 /searx/botdetection/trusted_proxies.py
parent8d3dd0cd451964d65bfecb54d6238a0b2e0f3a09 (diff)
[fix] py: (un)trusted proxies (#6556)
A missing condition allowed an attacker to mask their IP address from the server. This exploit can only be carried under specific client & server environments. Reported-by: Raffaele Forte <raffaele@backbox.org> Signed-off-by: Ivan Gabaldon <igabaldon@inetol.net>
Diffstat (limited to 'searx/botdetection/trusted_proxies.py')
-rw-r--r--searx/botdetection/trusted_proxies.py48
1 files changed, 29 insertions, 19 deletions
diff --git a/searx/botdetection/trusted_proxies.py b/searx/botdetection/trusted_proxies.py
index 4fb4c04ab..1e4c68837 100644
--- a/searx/botdetection/trusted_proxies.py
+++ b/searx/botdetection/trusted_proxies.py
@@ -63,6 +63,20 @@ class ProxyFix:
proxy_list: list[str] = cfg.get("botdetection.trusted_proxies", default=[])
return [ip_network(net, strict=False) for net in proxy_list]
+ def is_trusted_proxy(
+ self,
+ addr: IPv4Address | IPv6Address | None,
+ trusted_proxies: list[IPv4Network | IPv6Network],
+ ) -> bool:
+ if addr is None:
+ return False
+
+ for net in trusted_proxies:
+ if addr.version == net.version and addr in net:
+ return True
+
+ return False
+
def trusted_remote_addr(
self,
x_forwarded_for: list[IPv4Address | IPv6Address],
@@ -70,16 +84,8 @@ class ProxyFix:
) -> str:
# always rtl
for addr in reversed(x_forwarded_for):
- trust: bool = False
-
- for net in trusted_proxies:
- if addr.version == net.version and addr in net:
- logger.debug("trust proxy %s (member of %s)", addr, net)
- trust = True
- break
-
- # client address
- if not trust:
+ if not self.is_trusted_proxy(addr, trusted_proxies):
+ logger.debug("client address from X-Forwarded-For: %s", addr)
return addr.compressed
# fallback to first address
@@ -95,19 +101,21 @@ class ProxyFix:
# in this function!
orig_remote_addr: str | None = environ.pop("REMOTE_ADDR")
+ orig_remote_ip: IPv4Address | IPv6Address | None = None
# Validate the IPs involved in this game and delete all invalid ones
# from the WSGI environment.
if orig_remote_addr:
try:
- addr = ip_address(orig_remote_addr)
- if addr.version == 6 and addr.ipv4_mapped:
- addr = addr.ipv4_mapped
- orig_remote_addr = addr.compressed
+ orig_remote_ip = ip_address(orig_remote_addr)
+ if orig_remote_ip.version == 6 and orig_remote_ip.ipv4_mapped:
+ orig_remote_ip = orig_remote_ip.ipv4_mapped
+ orig_remote_addr = orig_remote_ip.compressed
except ValueError as exc:
logger.error("REMOTE_ADDR: %s / discard REMOTE_ADDR from WSGI environment", exc)
orig_remote_addr = None
+ orig_remote_ip = None
x_real_ip: str | None = environ.get("HTTP_X_REAL_IP")
if x_real_ip:
@@ -141,11 +149,13 @@ class ProxyFix:
if not x_forwarded_for and not x_real_ip:
log_error_only_once("X-Forwarded-For nor X-Real-IP header is set!")
- if x_forwarded_for and not trusted_proxies:
- log_error_only_once("missing botdetection.trusted_proxies config")
- # without trusted_proxies, this variable is useless for determining
- # the real IP
- x_forwarded_for = []
+ if x_forwarded_for or x_real_ip:
+ if not trusted_proxies:
+ log_error_only_once("missing botdetection.trusted_proxies config")
+
+ if not self.is_trusted_proxy(orig_remote_ip, trusted_proxies):
+ x_forwarded_for = []
+ x_real_ip = None
# securing the WSGI environment variables that are adjusted