From 2afa1d8c1d16dc7e5789419f070a0ce67624145b Mon Sep 17 00:00:00 2001 From: Moore Date: Mon, 29 Jun 2026 14:17:49 +0100 Subject: [PATCH] fix(#709): Enable TLS certificate validation in production - Set rejectUnauthorized: true in production SSL config - Add DB_SSL_CA environment variable for CA certificate path - Validate DB_SSL_CA is provided on module load in production - Development continues to allow unverified certificates - Document required environment variables in .env.example Fixes: Prevents man-in-the-middle attacks by enforcing TLS certificate verification in production database connections. --- .env.example | 6 ++++++ src/lib/db/pool.ts | 28 +++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index ae3ccd6a..c3b41639 100644 --- a/.env.example +++ b/.env.example @@ -31,6 +31,12 @@ DB_POOL_MAX=20 DB_CONNECTION_TIMEOUT=5000 DB_IDLE_TIMEOUT=30000 +# Database SSL Configuration (Required in production) +# Path to CA certificate file for TLS verification +# In production, this must be set to enable secure certificate validation +# Example: /etc/ssl/certs/ca-bundle.crt or /path/to/ca.pem +DB_SSL_CA= + # SMS Integration (#448) # Provider selection: twilio | sns | vonage (default: twilio) SMS_PROVIDER=twilio diff --git a/src/lib/db/pool.ts b/src/lib/db/pool.ts index f1fc9dd8..dfa312fc 100644 --- a/src/lib/db/pool.ts +++ b/src/lib/db/pool.ts @@ -13,12 +13,38 @@ import { retryWithBackoff } from '@/utils/errorUtils'; * - Query queueing during reconnect windows */ +/** + * Validate DB_SSL_CA is provided in production + */ +function validateSSLConfig(): void { + if (process.env.NODE_ENV === 'production' && !process.env.DB_SSL_CA) { + throw new Error( + 'DB_SSL_CA environment variable is required in production. ' + + 'This should contain the path to your CA certificate file.', + ); + } +} + +// Validate on module load +validateSSLConfig(); + +const getSSLConfig = () => { + if (process.env.NODE_ENV === 'production') { + return { + rejectUnauthorized: true, + ca: process.env.DB_SSL_CA, + }; + } + // Allow unverified certificates in development + return false; +}; + const DB_CONFIG: PoolConfig = { connectionString: process.env.DATABASE_URL, max: parseInt(process.env.DB_POOL_MAX || '20', 10), connectionTimeoutMillis: parseInt(process.env.DB_CONNECTION_TIMEOUT || '5000', 10), idleTimeoutMillis: parseInt(process.env.DB_IDLE_TIMEOUT || '30000', 10), - ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false, + ssl: getSSLConfig(), }; type CircuitState = 'CLOSED' | 'OPEN';