Files
crm-server/SECURITY_CHECK.md
richardtekula 109cae1167 Security improvements, role in user creation, todo filters fix
- 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>
2025-12-03 09:54:03 +01:00

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:

  • .env is 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 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

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:

  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)

    npm audit fix
    npm update
    
  2. Rotate all secrets (15 minutes)

    # 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)

  1. Implement session tracking in database
  2. Add session invalidation on password change
  3. Set up Dependabot/Snyk
  4. Enhance logging security

Month 2-3 (Medium Priority)

  1. Add virus scanning for files
  2. Implement 2FA
  3. Set up audit log retention
  4. Enhance password policies

📚 SECURITY RESOURCES


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)