[CRITICAL] Fix CORS configuration for cookie-based authentication #192

Closed
opened 2026-02-02 17:25:34 +00:00 by jason.woltje · 0 comments
Owner

Problem

CORS is configured with defaults (enableCors()) which allows all origins but doesn't enable credentials. This conflicts with cookie-based auth and risks a "credentials + wildcard origin" misconfiguration.

Locations

  • apps/api/src/main.ts:44 - enableCors() with defaults
  • apps/web/lib/client.ts:31 - credentials: "include"
// API
app.enableCors();  // ❌ Defaults to origin: '*'

// Web client  
fetch(url, {
  credentials: "include",  // ❌ Sends cookies but CORS blocks it
});

Issues

  1. Wildcard origin (*) with credentials rejected by browsers
  2. Cookie-based auth won't work across origins
  3. No CSRF protection
  4. Potential for credentials leakage if origin checking bypassed

Impact

  • CRITICAL: Authentication completely broken
  • Web client cannot access API
  • Session cookies not sent
  • Blocks production deployment
  • Security risk if wildcard + credentials misconfigured

Acceptance Criteria

  • Configure explicit allowed origins list
  • Enable credentials: true in CORS
  • Add CSRF token protection
  • Support multiple environments (dev/prod origins)
  • Document CORS configuration
  • Add tests for CORS headers
  • Verify cookies sent successfully

Implementation

// apps/api/src/main.ts
app.enableCors({
  origin: [
    process.env.WEB_URL || 'http://localhost:3000',
    process.env.ADDITIONAL_ORIGINS?.split(',') || []
  ].flat().filter(Boolean),
  credentials: true,
  methods: ['GET', 'POST', 'PATCH', 'DELETE', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization', 'X-Workspace-Id'],
  exposedHeaders: ['X-Total-Count'],
});

// Add CSRF protection
app.use(csurf({ 
  cookie: { 
    httpOnly: true, 
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'strict'
  } 
}));
// apps/web/lib/client.ts  
const csrfToken = getCsrfToken();

fetch(url, {
  credentials: "include",
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': csrfToken,
  },
});

Environment Variables

# .env
WEB_URL=http://localhost:3000
ADDITIONAL_ORIGINS=https://app.example.com,https://admin.example.com

Testing

  • Test API accessible from web client
  • Test cookies sent with requests
  • Test CORS preflight OPTIONS requests
  • Test CSRF token validation
  • Test unauthorized origin rejected

References

External security review findings (2026-02-02)

## Problem CORS is configured with defaults (enableCors()) which allows all origins but doesn't enable credentials. This conflicts with cookie-based auth and risks a "credentials + wildcard origin" misconfiguration. ## Locations - apps/api/src/main.ts:44 - enableCors() with defaults - apps/web/lib/client.ts:31 - credentials: "include" ```typescript // API app.enableCors(); // ❌ Defaults to origin: '*' // Web client fetch(url, { credentials: "include", // ❌ Sends cookies but CORS blocks it }); ``` ## Issues 1. Wildcard origin (*) with credentials rejected by browsers 2. Cookie-based auth won't work across origins 3. No CSRF protection 4. Potential for credentials leakage if origin checking bypassed ## Impact - **CRITICAL**: Authentication completely broken - Web client cannot access API - Session cookies not sent - Blocks production deployment - Security risk if wildcard + credentials misconfigured ## Acceptance Criteria - [ ] Configure explicit allowed origins list - [ ] Enable credentials: true in CORS - [ ] Add CSRF token protection - [ ] Support multiple environments (dev/prod origins) - [ ] Document CORS configuration - [ ] Add tests for CORS headers - [ ] Verify cookies sent successfully ## Implementation ```typescript // apps/api/src/main.ts app.enableCors({ origin: [ process.env.WEB_URL || 'http://localhost:3000', process.env.ADDITIONAL_ORIGINS?.split(',') || [] ].flat().filter(Boolean), credentials: true, methods: ['GET', 'POST', 'PATCH', 'DELETE', 'OPTIONS'], allowedHeaders: ['Content-Type', 'Authorization', 'X-Workspace-Id'], exposedHeaders: ['X-Total-Count'], }); // Add CSRF protection app.use(csurf({ cookie: { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'strict' } })); ``` ```typescript // apps/web/lib/client.ts const csrfToken = getCsrfToken(); fetch(url, { credentials: "include", headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrfToken, }, }); ``` ## Environment Variables ```bash # .env WEB_URL=http://localhost:3000 ADDITIONAL_ORIGINS=https://app.example.com,https://admin.example.com ``` ## Testing - [ ] Test API accessible from web client - [ ] Test cookies sent with requests - [ ] Test CORS preflight OPTIONS requests - [ ] Test CSRF token validation - [ ] Test unauthorized origin rejected ## References External security review findings (2026-02-02)
jason.woltje added this to the M4.2-Infrastructure (0.0.4) milestone 2026-02-02 17:25:34 +00:00
jason.woltje added the securityauthapiapip0 labels 2026-02-02 17:25:34 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaic/stack#192