Summary
APIKeyAuth accepts the API key via a ?api_key= query parameter, which causes secrets to leak into access logs, proxy logs, browser history, and HTTP Referer headers.
Context
At auth.go:86, after checking the X-API-Key header and Authorization: Bearer token, the middleware falls back to c.Query("api_key"). Query-string parameters are logged verbatim by virtually every reverse proxy (nginx, envoy, AWS ALB), appear in browser history and bookmark URLs, and are forwarded in Referer headers to any third-party resource loaded on the same page. A leaked API key grants full control-plane access. The query-param path was likely added for SSE client convenience but the tradeoff is not acceptable for general routes.
Scope
In Scope
- Remove the
?api_key= query-parameter fallback from APIKeyAuth for all standard REST routes.
- If SSE or WebSocket routes genuinely cannot set headers (browser
EventSource API), restrict query-param auth to an explicit allowlist of those streaming paths only.
- Document the allowlist decision with a comment.
Out of Scope
- Changing the header-based auth logic.
- Rotating or invalidating currently exposed keys — that is an ops action outside this PR.
- Adding OAuth or session-cookie auth — out of scope for this fix.
Files
control-plane/internal/server/middleware/auth.go:86 — remove or restrict the c.Query("api_key") fallback
control-plane/internal/server/routes.go — identify streaming routes that may need the restricted allowlist
control-plane/internal/server/middleware/auth_test.go — add test: request with ?api_key= on a standard REST route is rejected (401)
Acceptance Criteria
Notes for Contributors
Severity: MEDIUM
Check control-plane/internal/server/routes.go for any SSE endpoint registrations that use a browser EventSource — those are the only legitimate candidates for the allowlist. If none exist, remove the fallback entirely with no replacement.
Summary
APIKeyAuthaccepts the API key via a?api_key=query parameter, which causes secrets to leak into access logs, proxy logs, browser history, and HTTPRefererheaders.Context
At
auth.go:86, after checking theX-API-Keyheader andAuthorization: Bearertoken, the middleware falls back toc.Query("api_key"). Query-string parameters are logged verbatim by virtually every reverse proxy (nginx, envoy, AWS ALB), appear in browser history and bookmark URLs, and are forwarded inRefererheaders to any third-party resource loaded on the same page. A leaked API key grants full control-plane access. The query-param path was likely added for SSE client convenience but the tradeoff is not acceptable for general routes.Scope
In Scope
?api_key=query-parameter fallback fromAPIKeyAuthfor all standard REST routes.EventSourceAPI), restrict query-param auth to an explicit allowlist of those streaming paths only.Out of Scope
Files
control-plane/internal/server/middleware/auth.go:86— remove or restrict thec.Query("api_key")fallbackcontrol-plane/internal/server/routes.go— identify streaming routes that may need the restricted allowlistcontrol-plane/internal/server/middleware/auth_test.go— add test: request with?api_key=on a standard REST route is rejected (401)Acceptance Criteria
?api_key=query parameter (return 401)go test ./control-plane/...)make lint)Notes for Contributors
Severity: MEDIUM
Check
control-plane/internal/server/routes.gofor any SSE endpoint registrations that use a browserEventSource— those are the only legitimate candidates for the allowlist. If none exist, remove the fallback entirely with no replacement.