This guide provides detailed instructions for implementing the security fixes identified in the code review.
File: Backend/src/routes/auth.routes.js
Added missing Prisma client initialization:
const prisma = new PrismaClient();File: Backend/.env.example
Added the missing environment variable:
JWT_REFRESH_SECRET=your_super_secret_jwt_refresh_key_2024_taskforge_developmentUpgraded axios and vite packages to patched versions using npm audit fix.
Result: 0 vulnerabilities remaining in frontend.
File: Backend/src/utils/asyncHandler.js
Created a reusable async error handler wrapper.
File: Backend/src/server.js
Added 10MB limit to prevent DoS attacks:
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));File: Backend/src/config/db.js
Implemented exponential backoff retry logic with connection event handlers.
File: Backend/src/server.js
Added database connectivity checks for both MongoDB and PostgreSQL.
File: Backend/src/config/validateEnv.js
Created validation utility and integrated into server startup.
File: Backend/src/utils/passwordValidator.js
Utility for validating password requirements and calculating strength.
File: Backend/src/middleware/validate.js
Consistent validation error response format.
Issue: High severity vulnerability in graphql-upload package.
Current Version: <=14.0.0
Fixed Version: 17.0.0
Steps:
cd Backend
npm install graphql-upload@17.0.0Note: This is a breaking change. Review the migration guide before upgrading.
Alternative: If GraphQL upload functionality is not being used, consider removing it:
npm uninstall graphql-uploadPurpose: Prevent uncaught promise rejections that can crash the Node.js process.
Example Implementation:
// Before
router.post("/login", protect, async (req, res) => {
const user = await prisma.user.findUnique({ where: { email } });
res.json({ token });
});
// After
const asyncHandler = require('../utils/asyncHandler');
router.post("/login", protect, asyncHandler(async (req, res) => {
const user = await prisma.user.findUnique({ where: { email } });
res.json({ token });
}));Files to Update:
src/routes/auth.routes.jssrc/routes/task.routes.jssrc/routes/project.routes.jssrc/routes/comment.routes.jssrc/routes/admin.routes.jssrc/routes/report.routes.js
Current Issue: Hardcoded IP addresses in server.js
File: Backend/src/server.js
Before:
const allowedOrigins = [
"https://your-frontend-domain.com",
"http://localhost:3000",
"http://10.72.125.97:3000", // Hardcoded IP
"http://192.168.56.1:3000",
];After:
const allowedOrigins = process.env.CORS_ORIGIN?.split(',') || [
"http://localhost:3000",
"http://localhost:5173"
];Update .env.example:
# CORS Configuration
CORS_ORIGIN=http://localhost:3000,http://localhost:5173,https://your-production-domain.comFile: Backend/src/config/db.js
Current Code:
const connectMongo = async () => {
try {
await mongoose.connect(process.env.MONGO_URI);
console.log("✅ MongoDB connected");
} catch (err) {
console.error("❌ MongoDB connection error:", err);
}
};Improved Version:
const connectMongo = async (retries = 5) => {
for (let i = 0; i < retries; i++) {
try {
await mongoose.connect(process.env.MONGO_URI, {
serverSelectionTimeoutMS: 5000,
socketTimeoutMS: 45000,
});
console.log("✅ MongoDB connected");
return true;
} catch (err) {
console.error(`❌ MongoDB connection attempt ${i + 1}/${retries} failed:`, err.message);
if (i === retries - 1) {
console.error("❌ Failed to connect to MongoDB after multiple attempts");
process.exit(1); // Exit if database is unavailable
}
// Wait before retrying
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
};File: Backend/src/server.js
Current:
app.use(express.json());Updated:
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));Create: Backend/src/middleware/validate.js
const { validationResult } = require('express-validator');
/**
* Middleware to check validation results
* Use after express-validator validation chains
*/
const validate = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
success: false,
errors: errors.array()
});
}
next();
};
module.exports = validate;Usage:
const { body } = require('express-validator');
const validate = require('../middleware/validate');
router.post('/login',
body('email').isEmail().normalizeEmail(),
body('password').isLength({ min: 8 }),
validate, // Add this middleware
asyncHandler(async (req, res) => {
// Handler code
})
);File: Backend/src/server.js
Replace current health check with:
app.get('/api/health', asyncHandler(async (req, res) => {
const health = {
status: 'OK',
timestamp: new Date().toISOString(),
server: 'TaskForge Backend',
version: '1.0.0',
environment: process.env.NODE_ENV || 'development',
checks: {}
};
// Check MongoDB
try {
const mongoState = mongoose.connection.readyState;
health.checks.mongodb = {
status: mongoState === 1 ? 'connected' : 'disconnected',
state: mongoState
};
} catch (error) {
health.checks.mongodb = {
status: 'error',
message: error.message
};
}
// Check Prisma/PostgreSQL
try {
await prisma.$queryRaw`SELECT 1`;
health.checks.postgresql = {
status: 'connected'
};
} catch (error) {
health.checks.postgresql = {
status: 'error',
message: error.message
};
}
// Overall status
const allHealthy = Object.values(health.checks)
.every(check => check.status === 'connected');
health.status = allHealthy ? 'OK' : 'DEGRADED';
res.status(allHealthy ? 200 : 503).json(health);
}));Create: Backend/src/config/validateEnv.js
const requiredEnvVars = [
'NODE_ENV',
'PORT',
'JWT_SECRET',
'JWT_REFRESH_SECRET',
'DATABASE_URL',
'MONGO_URI'
];
const optionalEnvVars = [
'CLOUDINARY_CLOUD_NAME',
'CLOUDINARY_API_KEY',
'CLOUDINARY_API_SECRET',
'REDIS_URL'
];
function validateEnv() {
const missing = [];
for (const envVar of requiredEnvVars) {
if (!process.env[envVar]) {
missing.push(envVar);
}
}
if (missing.length > 0) {
console.error('❌ Missing required environment variables:');
missing.forEach(v => console.error(` - ${v}`));
console.error('\nPlease check your .env file against .env.example');
process.exit(1);
}
// Warn about optional variables
const missingOptional = optionalEnvVars.filter(v => !process.env[v]);
if (missingOptional.length > 0) {
console.warn('⚠️ Optional environment variables not set:');
missingOptional.forEach(v => console.warn(` - ${v}`));
console.warn('Some features may not work without these variables.\n');
}
console.log('✅ Environment variables validated');
}
module.exports = validateEnv;Usage in server.js:
require("dotenv").config();
const validateEnv = require('./config/validateEnv');
// Validate environment variables before starting
validateEnv();
// Rest of server.js...Create: Backend/src/utils/passwordValidator.js
/**
* Validate password strength
* Requirements:
* - Minimum 8 characters
* - At least one uppercase letter
* - At least one lowercase letter
* - At least one number
* - At least one special character
*/
function validatePasswordStrength(password) {
const minLength = 8;
const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password);
const hasNumbers = /\d/.test(password);
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password);
const errors = [];
if (password.length < minLength) {
errors.push(`Password must be at least ${minLength} characters long`);
}
if (!hasUpperCase) {
errors.push('Password must contain at least one uppercase letter');
}
if (!hasLowerCase) {
errors.push('Password must contain at least one lowercase letter');
}
if (!hasNumbers) {
errors.push('Password must contain at least one number');
}
if (!hasSpecialChar) {
errors.push('Password must contain at least one special character');
}
return {
isValid: errors.length === 0,
errors
};
}
module.exports = { validatePasswordStrength };Update: Backend/src/routes/auth.routes.js
const rateLimit = require('express-rate-limit');
// Stricter rate limit for login attempts
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // 5 attempts
message: 'Too many login attempts, please try again later',
standardHeaders: true,
legacyHeaders: false,
});
// Stricter rate limit for registration
const registerLimiter = rateLimit({
windowMs: 60 * 60 * 1000, // 1 hour
max: 3, // 3 registrations per hour
message: 'Too many accounts created, please try again later',
standardHeaders: true,
legacyHeaders: false,
});
router.post("/login", loginLimiter, /* ... other middleware ... */);
router.post("/register", registerLimiter, /* ... other middleware ... */);After implementing these fixes, test thoroughly:
- Test Environment Variables:
cd Backend
cp .env.example .env
# Fill in all required values
npm start- Test Health Endpoint:
curl http://localhost:4000/api/health- Test Authentication:
# Register
curl -X POST http://localhost:4000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"Test123!","username":"testuser"}'
# Login
curl -X POST http://localhost:4000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"Test123!"}'-
Test Rate Limiting: Try logging in 6 times quickly to trigger rate limiting.
-
Test Error Handling: Try invalid requests to ensure errors are properly caught.
- Prisma client initialized
- JWT_REFRESH_SECRET added to environment
- Frontend vulnerabilities fixed (0 remaining)
- Backend critical vulnerabilities fixed (sha.js, validator)
- Async handler utility created
- Request body size limits added
- Database connection retry logic added
- Health check enhanced with database checks
- Environment variable validation added
- Password strength validator created
- Standardized validation middleware created
- GraphQL upload package updated (requires breaking changes)
- Async handlers applied to all routes
- CORS origins moved to environment variables
- Rate limiting added to auth routes
- Add request ID tracking for better debugging
- Implement structured logging with Winston
- Add API documentation with Swagger
- Create unit tests for critical services
- Add integration tests for API endpoints
- Consider TypeScript migration
- Implement API versioning
- Add database indexes
- Implement caching strategy
- Add monitoring and observability
- Security audit by professional firm
- Performance optimization
- Load testing
- Disaster recovery plan
- CI/CD pipeline enhancements
Last Updated: 2025-11-08 Maintainer: Development Team