Skip to content

fix(api): require admin auth on /api/v1/logs (GHSA-m3qr-fvp4-78xj) - #506

Merged
xe-nvdk merged 3 commits into
mainfrom
fix/logs-endpoint-auth-ghsa-m3qr
Jun 15, 2026
Merged

xe-nvdk merged 3 commits into
mainfrom
fix/logs-endpoint-auth-ghsa-m3qr

Conversation

@xe-nvdk

@xe-nvdk xe-nvdk commented Jun 15, 2026

Copy link
Copy Markdown
Member

Addresses GHSA-m3qr-fvp4-78xj (private advisory). Ships in 26.06.2.

Summary

GET /api/v1/logs returned buffered application logs without authentication even with auth enabled (the default). The route was registered in Server.RegisterRoutes() among the public base routes — which runs before the global auth middleware (app.Use) is installed. Fiber v2 matches routes in registration order and returns on first match before reaching a later middleware, so the route bypassed auth. Reproduced on a running binary (unauth 200 → after fix 401).

Fix

  • Removed /api/v1/logs from RegisterRoutes; added Server.RegisterLogsRoute(authManager), called from main.go after app.Use(auth.NewMiddleware(...)). With auth enabled it wraps the handler in auth.RequireAdmin; with auth disabled (authManager == nil) it registers unguarded, preserving no-auth deployments.
  • Explicitly whitelisted the /api/v1/metrics prefix. Those JSON metrics endpoints were also registered pre-middleware, but they expose only aggregate counters + Go runtime/host-arch stats (equivalent to the public Prometheus /metrics surface — no queries, DB/measurement names, paths, or credentials) and are intentionally public. Codifying it makes their public status an auditable decision rather than an accident of route ordering.

Scope / severity

Exposure was operational log metadata only — component names, source locations, log messages, request outcomes. Arc does not write query text, database/measurement names, or credentials to this buffer, and the first-run admin-token banner uses stderr (not the logged buffer). Reconnaissance-grade info disclosure, not user-data or secret exposure.

Known limitation (recorded for the advisory, not changed here): the log buffer is global and admin is a global permission, so in a multi-tenant deployment an admin sees all orgs' log lines. Also pre-existing: logs access isn't captured by the audit middleware (registered later in the Fiber stack).

Test plan

  • go build -tags=duckdb_arrow ./cmd/... ./internal/..., go vet, gofmt -l clean
  • go test ./internal/api/... — all pass
  • New TestLogsEndpoint_RequiresAdmin (unauth 401 / read 403 / admin 200; health + metrics stay public) + TestLogsEndpoint_AuthDisabledStaysOpen (no-auth deploys unaffected); kill-switch verified
  • Internal config-matrix + Step 1b + deep reviewer + security-checklist reviewer (no Blockers/High)
  • Binary smoke: logs unauth→401, admin→200+content, read→403, /health+/api/v1/metrics→200, auth-disabled logs→200
  • Docs updated (docs.basekick.net branch docs/logs-endpoint-admin-auth)

Reported by @sondt99.

🤖 Generated with Claude Code

GET /api/v1/logs returned buffered application logs without
authentication even when auth was enabled (the default). It was
registered among the public base routes in Server.RegisterRoutes(),
which runs before the global auth middleware is installed; Fiber
matches routes in registration order and returns on first match before
reaching a later app.Use middleware, so the route bypassed auth.

Fix: register /api/v1/logs via Server.RegisterLogsRoute() AFTER the
auth middleware, wrapped with auth.RequireAdmin when auth is enabled
(unguarded when disabled, preserving no-auth deployments). Also
whitelist the /api/v1/metrics prefix explicitly: those JSON metrics
endpoints were likewise registered pre-middleware, but they expose
only aggregate counters and runtime stats (equivalent to the public
Prometheus /metrics surface) and are intentionally public — codifying
that makes it an auditable decision rather than an accident of order.

Exposure was operational log metadata only (component names, source
locations, messages, request outcomes); Arc does not log query text,
database/measurement names, or credentials to this buffer, and the
first-run admin-token banner uses stderr, not the logged buffer.

Regression test covers unauth (401), read-token (403), admin (200),
public routes (200), and the auth-disabled path (200). Verified on the
running binary.

Reported by @sondt99.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request secures the GET /api/v1/logs endpoint by ensuring it requires an admin token when authentication is enabled, addressing a vulnerability where it was previously exposed publicly due to route registration order. The logs route registration is moved after the global authentication middleware, and a new test suite is added to verify the authentication requirements. The review feedback correctly identifies that the http.Response bodies in the new tests should be closed to prevent potential resource leaks.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread internal/api/logs_auth_test.go Outdated
Comment thread internal/api/logs_auth_test.go Outdated

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request secures the GET /api/v1/logs endpoint by requiring an admin token when authentication is enabled, resolving a vulnerability where logs were exposed publicly due to route registration order. It also explicitly whitelists /api/v1/metrics as public and adds corresponding regression tests. Feedback suggests utilizing the existing withAdminAuth helper function in RegisterLogsRoute to eliminate manual conditional checks and maintain consistency.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread internal/api/server.go
…(Gemini round 1)

- RegisterLogsRoute now uses the existing withAdminAuth(authManager)
  helper (RequireAdmin when non-nil, passthrough when nil) instead of
  hand-rolled if/else — same semantics, consistent with every other
  authed route registration.
- Defer resp.Body.Close() on the app.Test responses in the logs-auth
  tests to avoid fd/memory leaks.
@xe-nvdk

xe-nvdk commented Jun 15, 2026

Copy link
Copy Markdown
Member Author

@gemini-code-assist Round-1 findings addressed: RegisterLogsRoute now uses the existing withAdminAuth helper (identical nil-handling, consistent with the rest of the package), and both app.Test responses defer resp.Body.Close(). Please take another look.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request addresses a security vulnerability (GHSA-m3qr-fvp4-78xj) by ensuring that the /api/v1/logs endpoint is registered after the global authentication middleware, thereby requiring an admin token when authentication is enabled. It also explicitly whitelists /api/v1/metrics as public and adds comprehensive integration tests. The review feedback suggests removing the -1 timeout parameter from app.Test calls in the new tests to prevent potential infinite hangs in CI/CD pipelines.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread internal/api/logs_auth_test.go Outdated
Comment thread internal/api/logs_auth_test.go Outdated
…ound 2)

app.Test(req, -1) disables the timeout; a hung handler/middleware would
block CI indefinitely. Use the default 1s timeout (app.Test(req)) — the
tests complete in milliseconds, so the timeout is pure safety net.
@xe-nvdk

xe-nvdk commented Jun 15, 2026

Copy link
Copy Markdown
Member Author

@gemini-code-assist Round-2 finding addressed: both app.Test calls now use the default 1s timeout instead of -1 (no infinite hang on a deadlock). Please take another look.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request secures the GET /api/v1/logs endpoint by requiring an admin token when authentication is enabled. Previously, the endpoint was registered among public base routes before the global authentication middleware, leaving it exposed. It is now registered after the authentication middleware, while /api/v1/metrics is explicitly whitelisted as public. Additionally, regression tests have been added to verify this behavior. There are no review comments to address, and we have no further feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@xe-nvdk
xe-nvdk merged commit bb7d976 into main Jun 15, 2026
5 checks passed
@xe-nvdk
xe-nvdk deleted the fix/logs-endpoint-auth-ghsa-m3qr branch June 15, 2026 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant