# Security & Functionality Fixes Applied **Date:** February 21, 2026 ## Summary of Fixes Applied ### Critical Fixes (Fixed) #### 1. Webhook Signature Verification Buffer Length Check **File:** `server.js:15162-15170` **Issue:** `timingSafeEqual()` throws error if buffer lengths differ, potentially bypassing verification. **Fix:** Added buffer length comparison before calling `timingSafeEqual()`. ```javascript const sigBuffer = Buffer.from(signature); const expectedBuffer = Buffer.from(expectedSignature); if (sigBuffer.length !== expectedBuffer.length || !require('crypto').timingSafeEqual(sigBuffer, expectedBuffer)) { // reject } ``` #### 2. Duplicate Variable Declaration in Webhook Handler **File:** `server.js:15253` **Issue:** `eventId` was declared twice in the same function scope, causing SyntaxError. **Fix:** Removed the duplicate declaration at line 15253. #### 3. Session Secret Auto-Generation with Persistence **File:** `server.js:390-420` **Issue:** Session secret was regenerated on each restart, invalidating all sessions. **Fix:** Session secret is now persisted to `generated-secrets.json` and reused on restart. ```javascript const secretsFile = path.join(STATE_DIR, 'generated-secrets.json'); // Load existing secret or generate and persist new one ``` #### 4. SQLCipher Key Validation **File:** `src/database/connection.js:18-29` **Issue:** SQLCipher key was only escaping quotes, not fully validating format. **Fix:** Added comprehensive key validation: - Minimum 32 characters - Must be hexadecimal only (0-9, a-f, A-F) ```javascript function validateSqlcipherKey(key) { if (!key || typeof key !== 'string') throw new Error('...'); if (key.length < 32) throw new Error('...'); if (!/^[a-fA-F0-9]+$/.test(key)) throw new Error('...'); return true; } ``` #### 5. JSON Body Size Limit in External API **File:** `src/external-admin-api/handlers.js:108-131` **Issue:** No size limit on JSON body parsing, potential memory exhaustion. **Fix:** Added `maxBodySize` parameter (default 6MB) with streaming size check. ```javascript async function parseJsonBody(req, maxBodySize = 6 * 1024 * 1024) { // ... size tracking and rejection if exceeded } ``` ### High Priority Fixes (Fixed) #### 6. CORS Headers **File:** `server.js:8940-8950` **Issue:** No explicit CORS configuration. **Fix:** Added comprehensive CORS headers to `sendJson()`: - `Access-Control-Allow-Origin` - `Access-Control-Allow-Methods` - `Access-Control-Allow-Headers` - `Access-Control-Allow-Credentials` #### 7. Pending Payment Session Cleanup **File:** `server.js:1130-1190` **Issue:** Pending payment sessions accumulate without cleanup. **Fix:** Added `cleanupStalePendingPayments()` function that: - Removes pending records older than 48 hours - Runs during periodic memory cleanup - Persists changes after cleanup #### 8. Builder State Debouncing **File:** `public/builder.js:19-46` **Issue:** Every property change triggered localStorage write (performance impact). **Fix:** Implemented debounced save with 500ms delay. ```javascript let builderStateSaveTimer = null; function saveBuilderState(state) { pendingBuilderState = state; if (builderStateSaveTimer) clearTimeout(builderStateSaveTimer); builderStateSaveTimer = setTimeout(() => { localStorage.setItem(BUILDER_STATE_KEY, JSON.stringify(pendingBuilderState)); }, 500); } ``` #### 9. Zip Extraction Symlink Protection **File:** `server.js:8950-8975` **Issue:** Extracted archives could contain symlinks pointing outside workspace. **Fix:** Added `scanForSymlinks()` function that removes symlinks after extraction. #### 10. Enhanced Environment Validation **File:** `server.js:20672-20720` **Issue:** Limited production environment checks. **Fix:** Enhanced validation with: - Critical variables check (DATABASE_ENCRYPTION_KEY added) - Recommended variables warnings - Better console output formatting ### Medium Priority Fixes (Fixed) #### 11. Dangerous File Type Blocking in Zip Extraction **File:** `server.js:8922-8927` **Fix:** Added blocking of potentially dangerous file types: - `.exe`, `.bat`, `.cmd`, `.sh`, `.ps1`, `.vbs` ## Files Modified 1. `chat/server.js` - Main server file (multiple fixes) 2. `chat/src/database/connection.js` - Database connection with SQLCipher validation 3. `chat/src/external-admin-api/handlers.js` - JSON body size limit 4. `chat/public/builder.js` - State persistence debouncing ## Remaining Recommendations (Non-Critical) These are recommended but not critical for launch: ### Post-Launch Items 1. **OAuth State in Database** - Currently stored in memory, will be lost on restart/multi-instance 2. **Atomic Token Operations** - Consider using database transactions for high-concurrency scenarios 3. **2FA for Admin** - Add two-factor authentication requirement for admin accounts 4. **IP-Based Admin Restrictions** - Consider limiting admin panel access by IP ## Testing Performed - Webhook signature verification with various buffer lengths - Session persistence across simulated restarts - SQLCipher key validation with various formats - JSON body parsing with oversized payloads - Builder state persistence under rapid changes - Zip extraction with path traversal attempts ## Verification Steps 1. **Webhook Test:** ```bash curl -X POST http://localhost:4000/webhooks/dodo \ -H "dodo-signature: sha256_invalid" \ -d '{"test": true}' # Should return 401, not crash ``` 2. **Session Persistence Test:** - Start server - Login as user - Restart server - Verify session still valid 3. **SQLCipher Test:** ```bash # Valid key DATABASE_ENCRYPTION_KEY=0123456789abcdef0123456789abcdef node server.js # Invalid key should fail with clear error DATABASE_ENCRYPTION_KEY="invalid!key" node server.js ``` ## Conclusion All critical and high-priority security and functionality issues have been addressed. The application is now ready for launch with the following improvements: - Robust webhook handling - Persistent session secrets - Validated SQLCipher keys - Protected JSON parsing - CORS support - Automatic cleanup of stale data - Better error handling and user feedback