fix: replace vulnerable email regex with safe alternatives

- Update isValidEmail in helpers.js with secure non-backtracking regex
- Use isValidEmail helper in auth.controller.js
- Use isValidEmail helper in contact.controller.js
- Replace regex with Zod .email() in newsletter.validation.js
- Fixes 5 SonarQube Security Hotspots for DoS via backtracking

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
soufiane 2025-12-05 15:03:36 +01:00
parent 62bb12f3a7
commit a7f82b1215
4 changed files with 15 additions and 10 deletions

View File

@ -4,7 +4,7 @@
import bcrypt from 'bcrypt';
import { pool } from '../../db.js';
import { AppError, asyncHandler } from '../middleware/errorHandler.js';
import { generateToken, generateJWT, getTokenExpiry, isExpired } from '../utils/helpers.js';
import { generateToken, generateJWT, getTokenExpiry, isExpired, isValidEmail } from '../utils/helpers.js';
import { sendResetPasswordEmail, sendWelcomeEmail } from '../services/email.service.js';
import dns from 'dns';
import { promisify } from 'util';
@ -330,9 +330,8 @@ export const checkEmail = asyncHandler(async (req, res, next) => {
return next(new AppError('Email requis', 400));
}
// Validation format email
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
// Validation format email (utilise isValidEmail pour éviter DoS)
if (!isValidEmail(email)) {
return res.json({
success: true,
isValid: false,

View File

@ -2,6 +2,7 @@
* Contrôleur pour gérer les messages de contact
*/
import { sendContactEmail } from '../services/email.service.js';
import { isValidEmail } from '../utils/helpers.js';
/**
* POST /api/contact
@ -19,9 +20,8 @@ export const submitContactForm = async (req, res) => {
});
}
// Validation email
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
// Validation email (utilise isValidEmail pour éviter DoS)
if (!isValidEmail(email)) {
return res.status(400).json({
success: false,
message: 'Adresse email invalide'

View File

@ -45,9 +45,13 @@ export const generateTicketCode = () => {
/**
* Valide le format d'un email
* Utilise une regex sécurisée (non-backtracking) pour éviter les attaques DoS
*/
export const isValidEmail = (email) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
// Limite la longueur pour éviter les attaques
if (!email || email.length > 254) return false;
// Regex simple et sécurisée (non-backtracking)
const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
return emailRegex.test(email);
};

View File

@ -10,7 +10,8 @@ export const subscribeSchema = z.object({
.string({
required_error: 'L\'email est requis',
})
.regex(/^[^\s@]+@[^\s@]+\.[^\s@]+$/, 'Format d\'email invalide'),
.email('Format d\'email invalide')
.max(254, 'Email trop long'),
}),
});
@ -21,7 +22,8 @@ export const unsubscribeSchema = z.object({
.string({
required_error: 'L\'email est requis',
})
.regex(/^[^\s@]+@[^\s@]+\.[^\s@]+$/, 'Format d\'email invalide'),
.email('Format d\'email invalide')
.max(254, 'Email trop long'),
}),
});