- Remove better-auth dependency (unused) - Update JWT secrets to stronger values - Add ENCRYPTION_SALT env variable for password encryption - Add role field to createUserSchema validator - Accept role from body in admin.controller createUser - Fix todo filters: add priority filter, handle completed param - Remove .env.example (merged into .env) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
17 KiB
🔒 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:
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:
- ✅
.envis properly gitignored - ✅ Never committed to git history
- ❌ Contains default/weak secrets that should be changed in production
Secrets Found:
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:
# Generate strong secrets:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# For each secret in .env:
JWT_SECRET=<generated-random-hex>
JWT_REFRESH_SECRET=<generated-random-hex>
BETTER_AUTH_SECRET=<generated-random-hex>
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:
environment:
POSTGRES_PASSWORD: heslo123
POSTGRES_DB: crm
POSTGRES_USER: admin
Recommendation:
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:
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:
// 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:
// 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:
// 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:
# 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:
// 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:
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:
const corsOptions = {
origin: process.env.CORS_ORIGIN || 'http://localhost:5173',
credentials: true,
optionsSuccessStatus: 200,
};
Enhanced:
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:
// 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:
// 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:
// 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:
// 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 fixto 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
# 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
# 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
# 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
# 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
# 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:
- Outdated dependencies with known vulnerabilities
- Secret management (default secrets in .env)
- Hardcoded salt in encryption
- 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:
-
Immediate Actions:
- Isolate affected systems
- Revoke all active sessions
- Rotate all secrets (JWT, database passwords)
- Enable maintenance mode
-
Investigation:
- Review audit logs
- Check for unauthorized access
- Identify attack vector
- Assess data exposure
-
Remediation:
- Patch vulnerabilities
- Update dependencies
- Reset affected user passwords
- Notify affected users (if required by law)
-
Prevention:
- Document incident
- Update security procedures
- Implement additional monitoring
- Conduct security training
📝 NEXT STEPS
Week 1 (Critical)
-
✅ Update dependencies (5 minutes)
npm audit fix npm update -
✅ Rotate all secrets (15 minutes)
# Generate new secrets node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" # Update .env with new values -
✅ Fix hardcoded salt (10 minutes)
- Update
src/utils/password.js - Test encryption/decryption still works
- Update
Week 2-4 (High Priority)
- Implement session tracking in database
- Add session invalidation on password change
- Set up Dependabot/Snyk
- Enhance logging security
Month 2-3 (Medium Priority)
- Add virus scanning for files
- Implement 2FA
- Set up audit log retention
- Enhance password policies
📚 SECURITY RESOURCES
- OWASP Top 10
- Node.js Security Best Practices
- Express.js Security Best Practices
- JWT Security Best Practices
- PostgreSQL Security
✅ 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:
- Update dependencies immediately
- Strengthen secret management
- Improve session security
- 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)