Skip to content

Comments

feat: auth hardening Sprint 19 (v0.7.0)#135

Merged
BadgerOps merged 10 commits intomasterfrom
feat/auth-hardening
Feb 18, 2026
Merged

feat: auth hardening Sprint 19 (v0.7.0)#135
BadgerOps merged 10 commits intomasterfrom
feat/auth-hardening

Conversation

@BadgerOps
Copy link
Owner

Summary

Auth hardening sprint implementing 13 security improvements for production readiness:

  • Auth-always default: Removed CLOUDPAM_AUTH_ENABLED toggle — authentication is now always required, with first-boot setup wizard for initial admin creation
  • P0 security fixes: Audit actor attribution from auth context, API key scope elevation prevention, bearer-as-session-token removal
  • Password policy: NIST 800-63B compliant — min 12 chars, max 72 (bcrypt boundary), validated on all user creation/password change flows
  • CSRF protection: Double-submit cookie pattern for session-authenticated requests, exempt for API key auth and login/setup endpoints
  • Session hardening: Max 10 concurrent sessions per user with oldest-eviction, revoke-all-sessions API (admin + self-service)
  • Login rate limiting: Per-IP token bucket (5 attempts/min default), trusted proxy support for X-Forwarded-For
  • Security settings UI: Config > Security page with session, password, login, and network settings — admin-only with live validation
  • Settings persistence: Key-value settings table with migration 0016, in-memory + SQLite store implementations

Breaking Changes

  • CLOUDPAM_AUTH_ENABLED env var removed — auth is always on
  • Bearer tokens that don't start with cpam_ are now rejected (previously treated as session tokens)
  • Minimum password length increased from 8 to 12 characters

New Endpoints

  • GET/PATCH /api/v1/settings/security — security settings management
  • POST /api/v1/auth/users/{id}/revoke-sessions — revoke all sessions for a user

New Environment Variables

  • CLOUDPAM_TRUSTED_PROXIES — comma-separated CIDRs for trusted reverse proxies

Test Plan

  • All Go tests pass (0 failures)
  • Linter clean (0 issues)
  • Default build succeeds
  • SQLite build succeeds (-tags sqlite)
  • TypeScript type check passes
  • Frontend builds successfully
  • CSRF tests (12 cases): cookie setting, token validation, API key bypass, login/setup exemptions
  • Password validation tests (7 cases): min/max length, empty, custom min
  • Login rate limiting tests (3 cases): below limit, over limit with 429, per-IP isolation
  • Trusted proxy tests (10 cases): parsing, trust checks, XFF extraction
  • Scope elevation tests (4 scenarios): operator→admin denied, admin→admin allowed
  • Session hardening tests (5 cases): revoke success/self-service/forbidden, ListByUserID, session limit enforcement
  • Settings handler tests (3 tests, 7 validation sub-cases)

Closes phase 1 of auth hardening. Phase 2 (SSO/OIDC) tracked in #130-#134.

🤖 Generated with Claude Code

BadgerOps and others added 10 commits February 18, 2026 11:34
- Remove RegisterRoutes() (unprotected variant)
- All routes now use RegisterProtectedRoutes() with RBAC
- Add missing import routes to protected registration
- BREAKING: CLOUDPAM_AUTH_ENABLED env var removed
- First boot always shows setup wizard
- Hardcode auth_enabled=true in /healthz response

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ymous

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ivileges than their own role

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add TrustedProxyConfig with CIDR-based proxy validation
- clientKey() now ignores X-Forwarded-For by default (secure default)
- Only trust XFF when direct peer is in CLOUDPAM_TRUSTED_PROXIES
- Add per-IP login rate limiting (5 attempts/min default)
- Login handler wrapped with LoginRateLimitMiddleware

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove Strategy 3 (Bearer token as session ID) from DualAuthMiddleware
- Sessions use cookies only; API keys use Bearer tokens (clean separation)
- Password minimum increased to 12 chars (NIST 800-63B)
- Password maximum enforced at 72 chars (bcrypt truncation boundary)
- ValidatePassword() used consistently in setup, user creation, and password change

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- SecuritySettings domain type with safe defaults
- SettingsStore interface with memory and SQLite implementations
- Migration 0016: settings table (key-value with JSON)
- GET/PATCH /api/v1/settings/security with RBAC (admin only)
- Full input validation on PATCH with bounds checking
- ResourceSettings added to RBAC permission model

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ListByUserID to SessionStore interface (memory, SQLite, PostgreSQL)
- Enforce max 10 concurrent sessions per user (evict oldest on overflow)
- POST /api/v1/auth/users/{id}/revoke-sessions endpoint
- Admin or self-service session revocation with audit logging

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Double-submit cookie pattern: csrf_token cookie + X-CSRF-Token header
- API key requests exempt (no cookies = no CSRF risk)
- Login and setup endpoints exempt (no session yet)
- Frontend API client sends CSRF token on all state-changing requests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- SecuritySettingsPage with session, password, login, network sections
- useSecuritySettings hook for GET/PATCH /api/v1/settings/security
- Sidebar link with Shield icon (admin only)
- Coming soon placeholders for Roles & Permissions and SSO/OIDC

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@BadgerOps BadgerOps merged commit 95cdeea into master Feb 18, 2026
16 checks passed
@BadgerOps BadgerOps deleted the feat/auth-hardening branch February 18, 2026 20:19
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