harden: fail-closed API auth, narrow container exposure, patch deps#1
Merged
Conversation
Security hardening of the control plane: - API auth now fails closed: an unset CONTROLPANE_API_AUTH_TOKEN returns 503 instead of allowing all traffic. Skipping auth requires the explicit CONTROLPANE_API_AUTH_DISABLED=1 opt-out. - Token comparison is now constant-time (hmac.compare_digest). - HTTP no longer accepts tokens via query string (they leak into logs/history); WebSocket query tokens are retained out of browser necessity. - WebSocket relay fails closed the same way as HTTP. - docker-compose: bind the API to loopback (127.0.0.1), pass through the auth token/disable vars, and mount only the managed runtime repos instead of the whole home tree. - Tighten dashboard CSP connect-src (drop broad https:/wss: wildcards). - Bump next 14.2.12 -> 14.2.35 (fixes CVE-2025-29927 and other 14.2.x advisories). - CI self-check opts out of auth explicitly; docs updated to match. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…names H3 - dashboard API token no longer ships to the browser: - Add a same-origin server route (app/api/cp/[...slug]/route.ts) that proxies all REST calls to the control-plane API and injects the token from a server-only env var (CONTROLPLANE_API_TOKEN). Verified the token never appears in the client bundle. - lib/api.ts and lib/controlplane.ts now call the same-origin BFF with no token. - WebSocket streams (which browsers cannot send headers on) become opt-in via a dedicated, clearly client-visible NEXT_PUBLIC_CONTROLPLANE_WS_TOKEN; when unset the dashboard falls back to REST polling through the authenticated BFF. - compose: dashboard reaches the API server-side over the compose network; bind the dashboard to loopback. L6 - env var spelling: - The canonical control-plane prefix is now CONTROLPLANE_. The historical misspelling CONTROLPANE_ is still honored as a deprecated alias, so correcting the spelling can never silently disable auth. - Updated config resolution, the smoke harness, compose, CI, and docs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Security hardening of the SquirrelOps control plane. Two batches of work:
Batch 1: auth, container exposure, deps
503instead of allowing all traffic. Skipping auth requires the explicitCONTROLPLANE_API_AUTH_DISABLED=1opt-out.hmac.compare_digest).127.0.0.1, pass through auth vars, mount only the managed runtime repos instead of the whole workspace.connect-src(drop broadhttps:/wss:wildcards).next14.2.12 -> 14.2.35 (fixes CVE-2025-29927 and other 14.2.x advisories).Batch 2: token off the client (H3) + env-var spelling (L6)
app/api/cp/[...slug]) that injects the token from a server-only env var. The token no longer ships in the client bundle (verified). WebSocket streams become opt-in via a dedicated, clearly client-visible token, with REST-polling fallback when unset.CONTROLPLANE_*is now canonical; the historical misspellingCONTROLPANE_*still works as a deprecated alias, so "fixing the typo" can never silently disable auth.Verification
.next/static.next build,py_compile,bash -n,docker compose config, and the CI self-check all pass.Known residual (documented, not in this PR)
actions-state.jsonwrite.🤖 Generated with Claude Code