From a04854800f77cffc3c4ef39fcfccddb896c4a185 Mon Sep 17 00:00:00 2001 From: coffee Date: Fri, 10 Apr 2026 11:56:23 +0800 Subject: [PATCH] fix(security): require auth for session continuation and warn on missing API key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two security hardening changes for the API server: 1. **Startup warning when no API key is configured.** When `API_SERVER_KEY` is not set, all endpoints accept unauthenticated requests. This is the default configuration, but operators may not realize the security implications. A prominent warning at startup makes the risk visible. 2. **Require authentication for session continuation.** The `X-Hermes-Session-Id` header allows callers to load and continue any session stored in state.db. Without authentication, an attacker who can reach the API server (e.g. via CORS from a malicious page, or on a shared host) could enumerate session IDs and read conversation history — which may contain API keys, passwords, code, or other sensitive data shared with the agent. Session continuation now returns 403 when no API key is configured, with a clear error message explaining how to enable the feature. When a key IS configured, the existing Bearer token check already gates access. This is defense-in-depth: the API server is intended for local use, but defense against cross-origin and shared-host attacks is important since the default binding is 127.0.0.1 which is reachable from browsers via DNS rebinding or localhost CORS. --- gateway/platforms/api_server.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/gateway/platforms/api_server.py b/gateway/platforms/api_server.py index 132790e5bd..e395516100 100644 --- a/gateway/platforms/api_server.py +++ b/gateway/platforms/api_server.py @@ -554,8 +554,26 @@ class APIServerAdapter(BasePlatformAdapter): # Allow caller to continue an existing session by passing X-Hermes-Session-Id. # When provided, history is loaded from state.db instead of from the request body. + # + # Security: session continuation exposes conversation history, so it is + # only allowed when the API key is configured and the request is + # authenticated. Without this gate, any unauthenticated client could + # read arbitrary session history by guessing/enumerating session IDs. provided_session_id = request.headers.get("X-Hermes-Session-Id", "").strip() if provided_session_id: + if not self._api_key: + logger.warning( + "Session continuation via X-Hermes-Session-Id rejected: " + "no API key configured. Set API_SERVER_KEY to enable " + "session continuity." + ) + return web.json_response( + _openai_error( + "Session continuation requires API key authentication. " + "Configure API_SERVER_KEY to enable this feature." + ), + status=403, + ) session_id = provided_session_id try: db = self._ensure_session_db() @@ -1675,6 +1693,14 @@ class APIServerAdapter(BasePlatformAdapter): await self._site.start() self._mark_connected() + if not self._api_key: + logger.warning( + "[%s] ⚠️ No API key configured (API_SERVER_KEY / platforms.api_server.key). " + "All requests will be accepted without authentication. " + "Set an API key for production deployments to prevent " + "unauthorized access to sessions, responses, and cron jobs.", + self.name, + ) logger.info( "[%s] API server listening on http://%s:%d (model: %s)", self.name, self._host, self._port, self._model_name,