Skip to content

feat(security): implement P1-P4 security hardening fixes - #277

Merged
2witstudios merged 2 commits into
masterfrom
security/hardening-p1-p4
Jan 29, 2026
Merged

2witstudios merged 2 commits into
masterfrom
security/hardening-p1-p4

Conversation

@2witstudios

@2witstudios 2witstudios commented Jan 29, 2026 •

Copy link
Copy Markdown
Owner

Summary

This PR implements the security hardening plan priorities 1-4, addressing critical security concerns identified in the security analysis.

P1: User Account Suspension Check

  • Added suspendedAt and suspendedReason fields to users schema
  • Updated user-validator.ts to check suspension status and return user_suspended failure reason
  • Updated session-service.ts to auto-revoke sessions when user is suspended
  • Files: packages/db/src/schema/auth.ts, apps/processor/src/services/user-validator.ts, packages/lib/src/auth/session-service.ts

P2: WebSocket Origin Validation Blocking

  • Changed validateAndLogWebSocketOrigin to return boolean and reject invalid origins (not just log)
  • Fail closed in production when no allowed origins configured (misconfiguration protection)
  • Non-browser clients (no Origin header) still allowed - they authenticate via tokens
  • Files: apps/realtime/src/index.ts

P3: SSRF DNS Rebinding Mitigation

  • Added buildIPDirectURL helper to connect directly to validated IPs
  • Modified safeFetch to use resolved IP with Host header preservation
  • Prevents TOCTOU attacks where DNS rebinds between validation and fetch
  • Files: packages/lib/src/security/url-validator.ts

P4: Service Token Audit Logging

  • Added structured security logging to processor auth middleware using loggers.security
  • Logs successful validations, failures, and scope assertion failures
  • Includes full request context (IP, endpoint, user agent, token prefix) in all logs
  • Files: apps/processor/src/middleware/auth.ts

P5: Legacy Cleanup

Database Migration

  • Added migration 0053_even_slayback.sql to add suspendedAt and suspendedReason columns to users table

Test plan

  • TypeScript typecheck passes
  • Run pnpm db:migrate to apply migration
  • Verify suspended user cannot authenticate via processor service
  • Verify WebSocket connections from invalid origins are rejected in production mode
  • Verify SSRF protection connects to validated IP (can test with mock DNS)
  • Verify security logs appear for processor authentication events

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • User account suspension support with configurable suspension reasons
    • Suspended accounts automatically block sessions and access
  • Security Improvements

    • Migration to database-backed opaque tokens (service tokens deprecated)
    • WebSocket connections now reject invalid origins
    • Mitigations against DNS-rebinding for internal requests
    • Improved structured security logging for auth events

✏️ Tip: You can customize this high-level summary in your review settings.

This PR implements the security hardening plan priorities 1-4:

**P1: User Account Suspension Check**
- Add suspendedAt/suspendedReason fields to users schema
- Update user-validator.ts to check suspension status
- Update session-service.ts to auto-revoke sessions for suspended users

**P2: WebSocket Origin Validation Blocking**
- Change validateAndLogWebSocketOrigin to return boolean and reject invalid origins
- Fail closed in production when no allowed origins configured
- Add proper logging for rejected connections

**P3: SSRF DNS Rebinding Mitigation**
- Add buildIPDirectURL helper to connect directly to validated IPs
- Modify safeFetch to use resolved IP with Host header preservation
- Prevents TOCTOU attacks where DNS rebinds between validation and fetch

**P4: Service Token Audit Logging**
- Add structured security logging to processor auth middleware
- Log successful validations, failures, and scope assertion failures
- Include request context (IP, endpoint, user agent) in all logs

**P5: Legacy Cleanup**
- Remove SERVICE_JWT_SECRET from .env.example and docker-compose.yml
- Mark vulnerabilities #1, #2, #11 as RESOLVED in security docs
- Update zero-trust-architecture.md to reflect opaque token migration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Jan 29, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds account suspension tracking and enforcement, replaces SERVICE_JWT_SECRET with database-backed opaque tokens, strengthens auth middleware logging, rejects disallowed WebSocket origins, and hardens SSRF/DNS-rebinding handling via IP-direct requests.

Changes

Cohort / File(s) Summary
Env & Compose examples
\.env.example, docker-compose.yml
Removed SERVICE_JWT_SECRET entries from examples/config.
Database Schema & Migrations
packages/db/src/schema/auth.ts, packages/db/drizzle/0053_even_slayback.sql, packages/db/drizzle/meta/_journal.json
Added suspendedAt (timestamp) and suspendedReason (text) to users and new migration/journal entry.
User Validation & Tests
apps/processor/src/services/user-validator.ts, apps/processor/src/services/__tests__/user-validator.test.ts
Added user_suspended failure reason, check for suspendedAt, and tests for suspended users; updated mocks.
Session Enforcement
packages/lib/src/auth/session-service.ts
Fetch suspendedAt during session validation; revoke sessions for suspended users with user_suspended reason.
Auth Middleware & Logging
apps/processor/src/middleware/auth.ts
Introduced structured requestContext, tokenPrefix tracing, and security-focused logging on missing/invalid tokens, scope failures, and successful validations.
WebSocket Origin Validation
apps/realtime/src/index.ts
Switched origin checks from log-only to fail-closed; added origin normalization, allowlist handling, and explicit allow/reject logging.
SSRF / URL Fetch Safety
packages/lib/src/security/url-validator.ts
Added buildIPDirectURL and logic to route HTTP fetches via resolved IP while preserving Host header to mitigate DNS rebinding; documented HTTPS limitations.
Web Test Fixtures
apps/web/src/app/api/auth/__tests__/*.test.ts
Added suspendedAt and suspendedReason (null) to mocked User fixtures across auth tests.
Docs
docs/3.0-guides-and-tools/cloud-security-analysis.md, docs/security/zero-trust-architecture.md
Updated security docs to reflect opaque-token migration, suspension checks, removed SERVICE_JWT_SECRET, and WebSocket origin enforcement.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant RealtimeServer as Realtime Server
  participant SessionService as Session Service / DB
  participant Logger
  Client->>RealtimeServer: Open WS connection (with Origin + token)
  RealtimeServer->>Logger: log incoming connection (origin, ip)
  RealtimeServer->>RealtimeServer: normalize & validate Origin
  alt origin allowed
    RealtimeServer->>SessionService: validate opaque token (session lookup)
    SessionService-->>RealtimeServer: session data (user, suspendedAt, scopes, sessionId)
    alt user suspended or session revoked
      RealtimeServer->>Logger: security.warn/revoke (tokenPrefix, userId, reason)
      RealtimeServer-->>Client: Reject connection (401/403)
    else valid session
      RealtimeServer->>Logger: security.info (sessionId, userId, scopes)
      RealtimeServer-->>Client: Accept connection
    end
  else origin disallowed
    RealtimeServer->>Logger: security.warn (origin rejected)
    RealtimeServer-->>Client: Reject connection
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • PR #184 — Foundational session/opaque-token infrastructure (sessions schema, opaque-token utilities, session-service) that this change relies on.
  • PR #187 — Also migrates service auth from JWTs to opaque sessions and updates middleware to use session-backed enforcement.
  • PR #232 — Overlaps on migration to database-backed opaque tokens and touches session/device token validation and related schema changes.

Poem

🐰 I nibble logs and guard the gate,
Tokens in vaults, suspended state,
Origins checked, rebinding banned,
Sessions revoked by careful hand,
Hopping home with audit bright — secure tonight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat(security): implement P1-P4 security hardening fixes' accurately summarizes the main objective of implementing multiple security priorities (P1-P4) related to user suspension, WebSocket validation, SSRF mitigation, and audit logging.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch security/hardening-p1-p4

Tip

🧪 Unit Test Generation v2 is now available!

We have significantly improved our unit test generation capabilities.

To enable: Add this to your .coderabbit.yaml configuration:

reviews:
  finishing_touches:
    unit_tests:
      enabled: true

Try it out by using the @coderabbitai generate unit tests command on your code files or under ✨ Finishing Touches on the walkthrough!

Have feedback? Share your thoughts on our Discord thread!


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/lib/src/security/url-validator.ts`:
- Around line 270-279: buildIPDirectURL causes HTTPS fetches to fail TLS
validation because SNI is set to the IP, not the original hostname; fix by not
using IP-direct URLs for https OR ensure the fetch uses an undici Agent with a
custom connector that sets servername to originalUrl.hostname; update the call
sites that consume buildIPDirectURL (and/or change buildIPDirectURL behavior)
to: for https requests either leave the URL host as the original hostname or, if
you must connect to the resolved IP, supply a dispatcher/Agent built with
buildConnector() and a connect override that passes
servername=originalUrl.hostname so SNI matches the certificate (refer to
buildIPDirectURL and the fetch/dispatcher logic that uses its return value).
🧹 Nitpick comments (2)
apps/processor/src/middleware/auth.ts (1)

100-103: Verify error type cast is safe.

The error is cast to Error for logging. If a non-Error object is thrown, this could result in incomplete log data.

🔧 Optional: Safer error handling
   } catch (error) {
-    loggers.security.error('Processor auth: validation error', error as Error, {
+    loggers.security.error('Processor auth: validation error', error instanceof Error ? error : new Error(String(error)), {
       ...requestContext,
       tokenPrefix,
     });
apps/realtime/src/index.ts (1)

101-108: Consider validating ADDITIONAL_ALLOWED_ORIGINS format.

The parsing silently ignores invalid URLs (empty strings after normalization), which is safe but could mask configuration errors.

💡 Optional: Log warning for invalid entries
   const additionalOrigins = process.env.ADDITIONAL_ALLOWED_ORIGINS;
   if (additionalOrigins) {
-    const parsed = additionalOrigins
+    const entries = additionalOrigins.split(',').map((o) => o.trim());
+    const parsed = entries
-      .split(',')
-      .map((o) => normalizeOrigin(o.trim()))
+      .map((o) => normalizeOrigin(o))
       .filter((o) => o.length > 0);
+    const invalidCount = entries.length - parsed.length;
+    if (invalidCount > 0) {
+      loggers.realtime.warn('ADDITIONAL_ALLOWED_ORIGINS contains invalid entries', {
+        totalEntries: entries.length,
+        validEntries: parsed.length,
+      });
+    }
     origins.push(...parsed);
   }

Comment thread packages/lib/src/security/url-validator.ts
- Fix logger import path: @pagespace/lib/logger-config -> @pagespace/lib/logging/logger-config
- Fix SSRF DNS rebinding for HTTPS: Skip IP-direct URLs for HTTPS because TLS/SNI requires hostname
- Add safer error type casting in auth middleware (error instanceof Error check)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@2witstudios

Copy link
Copy Markdown
Owner Author

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

@2witstudios
2witstudios merged commit d4c9bfc into master Jan 29, 2026
10 checks passed
@2witstudios
2witstudios deleted the security/hardening-p1-p4 branch January 30, 2026 00:18
2witstudios added a commit that referenced this pull request Aug 8, 2026
…ion-guard

fix(ai): settle CodeQL alert #277 on the consult route without weakening its check
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