From a0354c335b906bb785f5063cbe91b80d771f38d2 Mon Sep 17 00:00:00 2001 From: "Gan, Jimmy" Date: Fri, 27 Feb 2026 23:48:34 +0800 Subject: [PATCH] fix: trust docker gateway IP for reverse proxy auth --- dashboard/backend/config.py | 19 +++++++++++++++++++ dashboard/backend/main.py | 3 ++- dashboard/backend/routers/auth.py | 5 +++-- dashboard/backend/routers/system.py | 3 ++- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/dashboard/backend/config.py b/dashboard/backend/config.py index 84a1f23..1afee27 100644 --- a/dashboard/backend/config.py +++ b/dashboard/backend/config.py @@ -60,3 +60,22 @@ def is_lan_ip(ip_str: str) -> bool: return False except ValueError: return False + +TRUSTED_PROXIES = os.environ.get("TRUSTED_PROXIES", "127.0.0.1,::1,172.16.0.0/12,10.0.0.0/8").split(",") + +def is_trusted_proxy(ip_str: str) -> bool: + import ipaddress + try: + ip_obj = ipaddress.ip_address(ip_str) + for subnet_str in TRUSTED_PROXIES: + subnet_str = subnet_str.strip() + if "/" in subnet_str: + if ip_obj in ipaddress.ip_network(subnet_str): + return True + else: + if ip_obj == ipaddress.ip_address(subnet_str): + return True + return False + except ValueError: + return False + diff --git a/dashboard/backend/main.py b/dashboard/backend/main.py index dbc911f..f4c6034 100644 --- a/dashboard/backend/main.py +++ b/dashboard/backend/main.py @@ -119,7 +119,8 @@ async def health(): @app.get("/api/client-ip") async def client_ip(request: Request): ip = request.client.host - if ip in ("127.0.0.1", "::1"): + import config + if config.is_trusted_proxy(ip): forwarded = request.headers.get("x-forwarded-for", "").split(",")[0].strip() if forwarded: ip = forwarded diff --git a/dashboard/backend/routers/auth.py b/dashboard/backend/routers/auth.py index 8ec7acf..16e088f 100644 --- a/dashboard/backend/routers/auth.py +++ b/dashboard/backend/routers/auth.py @@ -113,8 +113,9 @@ async def login(creds: LoginRequest, request: Request): async def proxy_auth(request: Request): """Auto-login when Authelia has already authenticated the user via forward-auth. Caddy sets Remote-User header after successful Authelia 2FA verification.""" - # Prevent IP spoofing: ensure proxy traffic is from localhost (Caddy) - if request.client.host not in ("127.0.0.1", "::1"): + # Prevent IP spoofing: ensure proxy traffic is from trusted proxy network + import config + if not config.is_trusted_proxy(request.client.host): logger.warning(f"Rejected proxy auth attempt from unauthorized IP: {request.client.host}") raise HTTPException(status_code=403, detail="Unauthorized proxy source") diff --git a/dashboard/backend/routers/system.py b/dashboard/backend/routers/system.py index 6f17f7d..c42f323 100644 --- a/dashboard/backend/routers/system.py +++ b/dashboard/backend/routers/system.py @@ -117,7 +117,8 @@ def _classify(method, path, status, user): @router.get("/openclaw-token") def openclaw_token(request: Request): ip = request.client.host - if ip in ("127.0.0.1", "::1"): + import config + if config.is_trusted_proxy(ip): forwarded = request.headers.get("x-forwarded-for", "").split(",")[0].strip() if forwarded: ip = forwarded