From c4d3699669680c16f648f9843bd34810136f1e88 Mon Sep 17 00:00:00 2001 From: Chaim Date: Sat, 25 Apr 2026 18:27:03 +0000 Subject: [PATCH] fix(security): suppress uvicorn server-version banner + trust proxy headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - server_header=False — uvicorn was adding "server: uvicorn" after our middleware ran, defeating the banner-strip in security_headers(). - proxy_headers + forwarded_allow_ips=* — so request.client.host reflects the real client IP from X-Forwarded-For (Traefik), which is what the per-IP rate limiter keys on. Co-Authored-By: Claude Opus 4.7 (1M context) --- run_http_server.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/run_http_server.py b/run_http_server.py index 8a4a559..b913701 100644 --- a/run_http_server.py +++ b/run_http_server.py @@ -40,7 +40,19 @@ def main() -> None: logger.info(f" Health: http://{host}:{port}/health") logger.info("=" * 60) try: - uvicorn.run(app, host=host, port=port, log_level="info") + # server_header=False stops uvicorn from advertising its name+version; + # date_header=False is harmless and trims one more byte of fingerprint. + # proxy_headers=True + forwarded_allow_ips="*" so request.client.host + # reflects the real client IP behind Traefik (used by the rate limiter). + uvicorn.run( + app, + host=host, + port=port, + log_level="info", + server_header=False, + proxy_headers=True, + forwarded_allow_ips="*", + ) except Exception as e: logger.error(f"Failed to start HTTP server: {e}", exc_info=True) sys.exit(1)