Skip to content

[Security] API key accepted via ?api_key= query parameter #423

@santoshkumarradha

Description

@santoshkumarradha

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

  • Standard REST endpoints reject requests that authenticate only via ?api_key= query parameter (return 401)
  • If an SSE allowlist is implemented, only allowlisted routes accept query-param auth
  • Existing header-based auth tests continue to pass
  • Tests pass (go test ./control-plane/...)
  • Linting passes (make lint)

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:control-planeControl plane server functionalitybugSomething isn't workingsecuritySecurity vulnerability

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions