security(auth): timing-safe compare, cookie session, remove query token#10
Open
BRlin-o wants to merge 3 commits into
Open
security(auth): timing-safe compare, cookie session, remove query token#10BRlin-o wants to merge 3 commits into
BRlin-o wants to merge 3 commits into
Conversation
Network surface reduction (Phase 0): - Bind 127.0.0.1 by default; add HOST env for opt-in network access - Cap request body at 50 MB (CCXRAY_MAX_BODY_MB); return 413 on exceed - Per-IP SSE connection limit (default 8, CCXRAY_SSE_MAX_PER_IP) - HTTP timeouts: headersTimeout=60s, requestTimeout=120s, keepAliveTimeout=5s - Sanitize ANSI/control chars in logged request URLs (log injection) - Extract readBodyCapped() helper for safe body accumulation Filesystem hardening (Phase 1): - Log files 0o600, log directories 0o700; chmod on existing paths - safeJoin() rejects path traversal (../, /, \, null bytes) - Hub lockfile and log written with 0o600 Hub localhost-only + validation (Phase 2): - /_api/hub/* restricted to loopback IPs (127.0.0.1, ::1, ::ffff:127.0.0.1) - /_api/health remains open (pure liveness, no sensitive info) - Register/unregister validate pid (int, 0 < n ≤ 2²²) and cwd (string, ≤ 4096) - Hub body cap 1 KB for control endpoints BREAKING: Server now binds 127.0.0.1 only. Set HOST=0.0.0.0 for LAN access. Closes lis186#7 (partial) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bumps basic-ftp to patched version, resolving HIGH severity CRLF injection in @aws-sdk transitive dependency. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace === with crypto.timingSafeEqual for bearer token comparison; constant-time even on length mismatch - Remove ?token= query param auth (leaks in browser history, Referer, logs) - Add POST /login + POST /logout with HttpOnly cookie session (SameSite=Strict, Secure on non-loopback, 7-day TTL) - HTML Accept requests get 302 to /login.html; API requests get 401 JSON - Add login.html / login.js — minimal token input form - Per-process HMAC secret (sessions invalidate on restart — acceptable for a local dev tool) BREAKING: ?token=XXX query auth removed. Use Authorization: Bearer header (CLI/curl) or the new /login.html flow (browser). Closes lis186#7 (partial) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4 tasks
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
Auth hardening for ccxray. Part 2 of 3 PRs from the audit in #7.
Depends on #9 (network surface hardening).
crypto.timingSafeEqualwith constant-time length handling (no early return on length mismatch)?token=query param — leaked in browser history, Referer headers, and proxy logsPOST /loginvalidates token and sets HttpOnly cookie (SameSite=Strict,Secureon non-loopback, 7-day TTL).POST /logoutclears it.GET /login.htmlserves a minimal token input form. HTML clients get 302 redirect on 401; API clients get JSON.Breaking changes
?token=XXXquery auth removed. CLI/curl continues to work withAuthorization: Bearer.AUTH_TOKENnow goes through/login.htmlinstead of URL param.Test plan
test/auth.test.jsrewritten (11 cases): no-token, wrong Bearer, length-mismatch timing-safe, query param rejection, HTML accept 302, JSON accept 401, /login bypass, valid/tampered cookietest/login.test.js(7 cases): correct/wrong token, cookie session, logout, GET /login 405, Bearer compat, query param rejectionAUTH_TOKENset — redirects to login, token input works, cookie persistsRef: #7
🤖 Generated with Claude Code