# 🔒 SECURITY AUDIT REPORT - CRM Server **Date:** 2025-12-02 **Auditor:** Automated Security Scan **Project Version:** 1.0.0 **Node Version:** 20.x --- ## Executive Summary I've completed a comprehensive security audit of your CRM server project. The project has **good security foundations** with several protective measures in place, but there are **2 critical dependency vulnerabilities** and several **medium-priority security improvements** needed. --- ## ✅ STRENGTHS ### 1. **Authentication & Authorization** - ✅ JWT tokens stored in httpOnly cookies (XSS protection) - ✅ SameSite=Strict cookies (CSRF protection) - ✅ Bcrypt password hashing (12 rounds) - ✅ Separate access & refresh tokens - ✅ Role-based access control (admin/member) - ✅ Temporary password system for onboarding ### 2. **Input Validation & Sanitization** - ✅ Zod schemas for request validation - ✅ XSS protection via xss-clean middleware - ✅ Custom malicious pattern detection in `validateBody.js` - ✅ SQL injection protection via Drizzle ORM (parameterized queries) ### 3. **Rate Limiting** - ✅ Login rate limiter (5 attempts/15min) - ✅ API rate limiter (100 req/15min production, 1000 dev) - ✅ Sensitive operations limiter (3 attempts/15min) ### 4. **Security Headers & CORS** - ✅ Helmet middleware with CSP and HSTS - ✅ Configured CORS with credentials support - ✅ Body size limits (10MB) ### 5. **Data Encryption** - ✅ AES-256-GCM for email passwords - ✅ Crypto.randomUUID() for tokens - ✅ Secure password generation ### 6. **File Upload Security** - ✅ File type whitelist (PDF, Excel only) - ✅ File size limit (10MB) - ✅ Memory storage (prevents path traversal) - ✅ Filename sanitization ### 7. **Docker Security** - ✅ Non-root user in Dockerfile - ✅ Alpine Linux base image (smaller attack surface) ### 8. **Audit Logging** - ✅ Comprehensive audit trail - ✅ IP address and user-agent tracking --- ## 🚨 CRITICAL VULNERABILITIES ### 1. **NPM Dependencies - 2 Low Severity Issues** ⚠️ **better-auth v1.3.34** (2 vulnerabilities): - **GHSA-wmjr-v86c-m9jj**: Multi-session sign-out hook allows forged cookies to revoke arbitrary sessions (CVSS 9.6) - Severity: Low (but high CVSS score) - Fix available: v1.4.4 - **GHSA-569q-mpph-wgww**: External request basePath modification DoS - Severity: Low - Fix available: v1.4.4 **express v4.21.2**: - **GHSA-pj86-cfqh-vqx6**: Improper control of query properties modification - Severity: Low - Fix available: v4.22.0 **Fix Available**: Yes **Recommended Action**: ```bash npm audit fix # This will update: # - better-auth: 1.3.34 → 1.4.4 # - express: 4.21.2 → 4.22.1 ``` **Additional Outdated Packages**: - `dotenv`: 16.6.1 → 17.2.3 (latest) - `zod`: 4.1.12 → 4.1.13 --- ## ⚠️ HIGH PRIORITY ISSUES ### 2. **Environment File Security** 🔴 **Issue**: `.env` file contains default/weak secrets **Findings**: - ✅ `.env` is properly gitignored - ✅ Never committed to git history - ❌ Contains default/weak secrets that should be changed in production **Secrets Found**: ```env JWT_SECRET=your-super-secret-jwt-key-change-this-in-production JWT_REFRESH_SECRET=your-super-secret-refresh-key-change-this-in-production BETTER_AUTH_SECRET=your-super-secret-better-auth-key-change-this-in-production ``` **Recommendation**: ```bash # Generate strong secrets: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" # For each secret in .env: JWT_SECRET= JWT_REFRESH_SECRET= BETTER_AUTH_SECRET= ``` **Best Practices**: - Generate strong, random secrets for production - Consider using secret management (HashiCorp Vault, AWS Secrets Manager) - Rotate secrets regularly (every 90 days) - Never commit secrets to version control ### 3. **Database Credentials in docker-compose.yml** 🟡 **Issue**: Hardcoded database password in docker-compose.yml **Current Code**: ```yaml environment: POSTGRES_PASSWORD: heslo123 POSTGRES_DB: crm POSTGRES_USER: admin ``` **Recommendation**: ```yaml environment: POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_DB: ${DB_NAME} POSTGRES_USER: ${DB_USER} ``` ### 4. **Password Encryption Salt** 🟡 **Location**: `src/utils/password.js:75` **Issue**: Hardcoded salt value 'salt' - should be unique per encryption **Current Code**: ```javascript const key = crypto.scryptSync(process.env.JWT_SECRET, 'salt', 32); ``` **Problem**: Using a static salt means all encrypted passwords use the same key derivation, reducing security. **Recommendation**: ```javascript // Generate random salt per encryption const salt = crypto.randomBytes(16); const key = crypto.scryptSync(process.env.JWT_SECRET, salt, 32); // Store: `${salt.toString('hex')}:${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted}` ``` --- ## 🟡 MEDIUM PRIORITY IMPROVEMENTS ### 5. **Session Security** **Current Issues**: - ❌ No session invalidation on password change - ❌ No maximum concurrent sessions per user - ❌ No session timeout warnings - ❌ Refresh tokens not stored in database (cannot revoke) **Recommendation**: ```javascript // Add session tracking table export const sessions = pgTable('sessions', { id: uuid('id').primaryKey().defaultRandom(), userId: uuid('user_id').references(() => users.id, { onDelete: 'cascade' }), refreshToken: text('refresh_token').notNull(), ipAddress: text('ip_address'), userAgent: text('user_agent'), expiresAt: timestamp('expires_at').notNull(), createdAt: timestamp('created_at').defaultNow() }); // Invalidate all sessions on password change // Limit to 5 concurrent sessions per user ``` ### 6. **Password Policy Enhancement** **Current Policy** (from code review): - ✅ Minimum 8 characters - ✅ Must contain uppercase, lowercase, number, symbol **Enhancements Needed**: ```javascript // Add to password validation: - Minimum 12 characters (currently 8) - Check against common password list (e.g., have-i-been-pwned) - Prevent password reuse (store hash of last 5 passwords) - Add password strength meter on frontend - Enforce password expiration (90 days for admin accounts) ``` ### 7. **File Storage Security** **Current Issues**: - ❌ Uploaded files stored locally without encryption at rest - ❌ No virus scanning on uploads - ❌ File paths somewhat predictable: `uploads/timesheets/{userId}/{year}/{month}/{filename}` **Recommendations**: ```bash # 1. Add virus scanning npm install clamscan # 2. Encrypt files at rest # Use node's crypto to encrypt files before saving # 3. Use UUIDs in paths uploads/timesheets/{uuid}/{uuid}.encrypted ``` **Alternative**: Migrate to cloud storage (AWS S3, Azure Blob) with server-side encryption ### 8. **Logging Concerns** **Issues**: - ❌ No check for sensitive data in logs - ⚠️ Morgan logs all requests (could expose sensitive query params) - ❌ Console.log statements in code (should use winston logger) **Recommendation**: ```javascript // Configure morgan to skip sensitive routes app.use(morgan('dev', { skip: (req) => { const sensitivePatterns = [ /password/i, /token/i, /secret/i, /api\/auth\/login/, /api\/auth\/set-password/ ]; return sensitivePatterns.some(pattern => pattern.test(req.url) || pattern.test(JSON.stringify(req.body)) ); } })); // Replace all console.log with winston logger import { logger } from './utils/logger.js'; ``` --- ## 🔵 LOW PRIORITY / BEST PRACTICES ### 9. **Security Headers Enhancement** **Current CSP** is basic. Enhance with: ```javascript app.use(helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'"], styleSrc: ["'self'", "'unsafe-inline'"], imgSrc: ["'self'", "data:", "https:"], connectSrc: ["'self'"], fontSrc: ["'self'"], objectSrc: ["'none'"], mediaSrc: ["'none'"], frameSrc: ["'none'"], upgradeInsecureRequests: [], }, }, hsts: { maxAge: 31536000, includeSubDomains: true, preload: true, }, referrerPolicy: { policy: "strict-origin-when-cross-origin" }, noSniff: true, xssFilter: true, hidePoweredBy: true })); ``` ### 10. **CORS Hardening** **Current**: ```javascript const corsOptions = { origin: process.env.CORS_ORIGIN || 'http://localhost:5173', credentials: true, optionsSuccessStatus: 200, }; ``` **Enhanced**: ```javascript const corsOptions = { origin: process.env.CORS_ORIGIN || 'http://localhost:5173', credentials: true, methods: ['GET', 'POST', 'PATCH', 'DELETE'], allowedHeaders: ['Content-Type', 'Authorization'], exposedHeaders: ['Content-Range', 'X-Content-Range'], maxAge: 86400, // 24 hours optionsSuccessStatus: 200 }; ``` ### 11. **Rate Limiting - IP Spoofing Protection** Add trust proxy setting: ```javascript // In app.js, before rate limiters app.set('trust proxy', 1); // Trust first proxy (nginx, cloudflare, etc.) ``` ### 12. **Audit Log Retention** **Current Issues**: - ❌ No automatic cleanup of old audit logs - ❌ No log rotation policy - ❌ Unlimited log growth **Recommendation**: ```javascript // Add cron job to clean old logs import cron from 'node-cron'; // Run daily at 2 AM cron.schedule('0 2 * * *', async () => { const retentionDays = 90; await db.delete(auditLogs) .where( sql`created_at < NOW() - INTERVAL '${retentionDays} days'` ); }); ``` ### 13. **Additional Security Measures** **API Security**: ```javascript // Add request ID tracking import { v4 as uuidv4 } from 'uuid'; app.use((req, res, next) => { req.id = uuidv4(); res.setHeader('X-Request-ID', req.id); next(); }); // Add timeout middleware import timeout from 'connect-timeout'; app.use(timeout('30s')); ``` **Brute Force Protection**: ```javascript // Add progressive delays after failed login attempts // Implement account lockout after 10 failed attempts // Add CAPTCHA after 3 failed attempts ``` --- ## 📋 SECURITY CHECKLIST ### 🔴 Immediate Actions (Do Now) - [ ] Run `npm audit fix` to update dependencies - [ ] Generate strong secrets for JWT_SECRET, JWT_REFRESH_SECRET, BETTER_AUTH_SECRET - [ ] Move database password to environment variable in docker-compose.yml - [ ] Fix hardcoded salt in password encryption (src/utils/password.js) ### 🟡 Short Term (This Week) - [ ] Implement session invalidation on password change - [ ] Add session tracking in database - [ ] Review and filter sensitive data from logs - [ ] Update password policy to 12 characters minimum - [ ] Add trust proxy setting for rate limiters ### 🔵 Medium Term (This Month) - [ ] Add virus scanning for file uploads - [ ] Implement password strength requirements and breach checking - [ ] Set up automated security scanning (Snyk, Dependabot) - [ ] Implement audit log retention policy - [ ] Add 2FA support - [ ] Enhance security headers (CSP, etc.) ### 🟢 Long Term (This Quarter) - [ ] Migrate to managed secrets (AWS Secrets Manager, HashiCorp Vault) - [ ] Implement file encryption at rest - [ ] Add honeypot endpoints - [ ] Set up SIEM/log aggregation - [ ] Conduct penetration testing - [ ] Implement zero-trust architecture --- ## 🔧 RECOMMENDED SECURITY TOOLS ### 1. **Dependency Scanning** ```bash # NPM Audit (built-in) npm audit npm audit fix # Snyk (more comprehensive) npm install -g snyk snyk auth snyk test snyk monitor # GitHub Dependabot # Enable in: Settings → Security & analysis → Dependabot alerts ``` ### 2. **Static Analysis** ```bash # ESLint security plugin npm install --save-dev eslint-plugin-security # Add to .eslintrc.json: "plugins": ["security"] # SonarQube # Self-hosted or SonarCloud for continuous inspection ``` ### 3. **Runtime Protection** ```bash # Helmet (already installed) ✅ # Express rate limit (already installed) ✅ # Additional recommendations: npm install express-mongo-sanitize # NoSQL injection prevention npm install hpp # HTTP Parameter Pollution protection npm install csurf # CSRF token middleware ``` ### 4. **Secret Scanning** ```bash # TruffleHog - scan git history for secrets docker run --rm -v "$(pwd):/repo" trufflesecurity/trufflehog:latest git file:///repo # GitLeaks docker run --rm -v "$(pwd):/path" zricethezav/gitleaks:latest detect --source="/path" ``` ### 5. **Penetration Testing** ```bash # OWASP ZAP docker run -t owasp/zap2docker-stable zap-baseline.py -t http://your-api # Burp Suite Community Edition # Manual testing of API endpoints ``` --- ## 📊 OVERALL SECURITY RATING ### **Score: 7.5/10** 🟢 ### Breakdown: | Category | Score | Status | |----------|-------|--------| | Authentication/Authorization | 9/10 | ✅ Excellent | | Input Validation | 8/10 | ✅ Good | | Dependency Management | 6/10 | ⚠️ Needs Update | | Encryption | 7/10 | 🟡 Good with improvements needed | | Secret Management | 6/10 | ⚠️ Needs Improvement | | Network Security | 9/10 | ✅ Excellent | | Audit/Logging | 7/10 | 🟡 Good | | File Upload Security | 7/10 | 🟡 Good | | Session Management | 6/10 | 🟡 Needs Improvement | | Error Handling | 8/10 | ✅ Good | ### **Verdict**: Your project has a **solid security foundation** with industry-standard practices including JWT authentication, bcrypt hashing, rate limiting, and input validation. The main concerns are: 1. Outdated dependencies with known vulnerabilities 2. Secret management (default secrets in .env) 3. Hardcoded salt in encryption 4. Session management improvements needed Addressing the critical and high-priority issues will bring your security posture to **production-ready** status. --- ## 🎯 COMPLIANCE CONSIDERATIONS ### GDPR (EU Data Protection) - ✅ Audit logging for data access - ✅ Data deletion (cascade deletes) - ❌ Missing: Right to data portability (export user data) - ❌ Missing: Consent management - ❌ Missing: Data retention policies ### SOC 2 (Security & Availability) - ✅ Access controls - ✅ Encryption in transit (HTTPS) - ✅ Audit logging - ⚠️ Missing: Encryption at rest for files - ⚠️ Missing: Backup and disaster recovery procedures ### OWASP Top 10 2021 - ✅ A01: Broken Access Control - Protected ✅ - ✅ A02: Cryptographic Failures - Mostly Protected ⚠️ - ✅ A03: Injection - Protected ✅ - ✅ A04: Insecure Design - Good architecture ✅ - ⚠️ A05: Security Misconfiguration - Minor issues ⚠️ - ✅ A06: Vulnerable Components - Needs update ⚠️ - ✅ A07: Authentication Failures - Protected ✅ - ✅ A08: Data Integrity Failures - Protected ✅ - ✅ A09: Logging Failures - Good but can improve 🟡 - ✅ A10: SSRF - Not applicable to this architecture ✅ --- ## 📞 INCIDENT RESPONSE PLAN ### If Security Breach Detected: 1. **Immediate Actions**: - Isolate affected systems - Revoke all active sessions - Rotate all secrets (JWT, database passwords) - Enable maintenance mode 2. **Investigation**: - Review audit logs - Check for unauthorized access - Identify attack vector - Assess data exposure 3. **Remediation**: - Patch vulnerabilities - Update dependencies - Reset affected user passwords - Notify affected users (if required by law) 4. **Prevention**: - Document incident - Update security procedures - Implement additional monitoring - Conduct security training --- ## 📝 NEXT STEPS ### Week 1 (Critical) 1. ✅ **Update dependencies** (5 minutes) ```bash npm audit fix npm update ``` 2. ✅ **Rotate all secrets** (15 minutes) ```bash # Generate new secrets node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" # Update .env with new values ``` 3. ✅ **Fix hardcoded salt** (10 minutes) - Update `src/utils/password.js` - Test encryption/decryption still works ### Week 2-4 (High Priority) 4. Implement session tracking in database 5. Add session invalidation on password change 6. Set up Dependabot/Snyk 7. Enhance logging security ### Month 2-3 (Medium Priority) 8. Add virus scanning for files 9. Implement 2FA 10. Set up audit log retention 11. Enhance password policies --- ## 📚 SECURITY RESOURCES - [OWASP Top 10](https://owasp.org/www-project-top-ten/) - [Node.js Security Best Practices](https://nodejs.org/en/docs/guides/security/) - [Express.js Security Best Practices](https://expressjs.com/en/advanced/best-practice-security.html) - [JWT Security Best Practices](https://datatracker.ietf.org/doc/html/rfc8725) - [PostgreSQL Security](https://www.postgresql.org/docs/current/security.html) --- ## ✅ CONCLUSION Your CRM server demonstrates **good security awareness** with proper implementation of authentication, authorization, input validation, and rate limiting. The identified vulnerabilities are **manageable and fixable** within a reasonable timeframe. **Priority focus areas**: 1. Update dependencies immediately 2. Strengthen secret management 3. Improve session security 4. Enhance file upload security With these improvements, your application will achieve **production-grade security** suitable for handling sensitive customer data. --- **Report Generated**: 2025-12-02 **Next Review Recommended**: 2025-03-02 (Quarterly) **Security Contact**: security@your-domain.com (update this)