Skip to content

[security] Bearer tokens accepted via ?token= query string on all protected routes #449

Description

@dcmcand

Summary

The auth middleware falls back to reading the bearer token from a ?token= URL query parameter, and this fallback is attached to the entire protected route group rather than only the SSE log-stream route that needs it. Long-lived (24-hour) tokens can therefore appear in URLs on every protected endpoint. (CWE-598 Use of GET Request Method with Sensitive Query Strings.)

Where it is (verified against main @ 15f66d4)

  • The middleware checks the Authorization header and otherwise sets tokenString = c.Query("token"): internal/auth/basic.go:168-171 (the only Query("token") in the codebase). The comment cites EventSource/SSE compatibility.
  • The middleware is applied to the whole protected group: internal/api/router.go:196-197 (protected := base.Group("/api/v1"); protected.Use(authenticator.Middleware())), covering workspaces, jobs, registries, groups, admin, and remote routes - not just the stream.
  • The only route that genuinely needs it is the SSE job-log stream GET /jobs/:id/logs/stream (internal/api/handlers/job.go:82, route at router.go:250), because EventSource cannot set headers.
  • Tokens are valid 24 hours (internal/auth/basic.go:26).

Impact

JWTs can be written to browser history, reverse-proxy and load-balancer logs, APM/monitoring tools, screenshots, copied URLs, and referrer headers. A leaked token grants the user's application privileges until expiry or key rotation.

Remediation

  • Accept query credentials only on the exact SSE endpoint, or replace it with fetch() streaming using an Authorization header, or issue a single-purpose, job-bound, short-lived stream capability.
  • Reject query tokens on every other route.
  • Redact sensitive query parameters in all logging layers; shorten JWT lifetime and add revocation/refresh.

Acceptance criteria

  • ?token= receives 401 on all ordinary protected endpoints.
  • A stream token cannot access another job or any non-stream route, and expires within minutes.
  • Access logs contain no bearer material.

Identified in a security assessment of v0.13 (commit be3187c), re-validated against main @ 15f66d4. Confidence: High.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ares: securitySecurity-related finding (vulnerability or hardening)priority: medium ⚡Medium priority - standard queue

    Type

    No type

    Fields

    Priority

    None yet

    Start date

    None yet

    Target date

    None yet

    Size

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions