flawopen.com/ReDoS/JavaScript RegExp
JavaScript RegExp est-il vulnérable à ReDoS ?
Imaginez un employé qui essaie toutes les façons de répartir une pile de formulaires lorsqu’il manque la marque finale : un motif ambigu peut obliger le moteur regex à reparcourir les mêmes caractères. Le chemin RegExp habituel de V8 peut revenir en arrière ainsi ; limiter l’entrée et choisir un motif au coût prévisible borne le travail. Dans Node, la correspondance synchrone s’exécute sur le thread de l’event loop et retarde les autres callbacks du processus. V8 documente un moteur expérimental sans backtracking, activé par des options et limité pour certains motifs ; ne supposez pas qu’il soit activé en production.
// Répétition imbriquée ambiguë dans les données de requête
const re = /^(\w+\s?)*$/;
app.post('/search', (req, res) => {
const q = req.body.q;
if (!re.test(q)) return res.sendStatus(400);
res.sendStatus(200);
});
// Bornez l’entrée et acceptez uniquement la grammaire du champ
app.post('/search', (req, res) => {
const q = req.body.q;
if (typeof q !== 'string' || q.length > 128)
return res.sendStatus(400);
// Grammaire exemple : caractères ASCII de mot et espaces
if (!/^[\w ]{1,128}$/.test(q))
return res.sendStatus(400);
res.sendStatus(200);
});
Pourquoi Node.js amplifie l’impact de ReDoS
Une correspondance regex synchrone s’exécute sur le thread JavaScript qui traite les callbacks d’un processus Node.js. Si un motif prend longtemps sur une quasi-correspondance ou un échec, cet event loop ne peut exécuter les autres callbacks ni faire avancer les requêtes avant la fin. Des workers, plusieurs processus ou réplicas peuvent préserver une partie de la capacité, mais chaque processus touché peut rester bloqué.
L’impact dépend de l’accessibilité, de la complexité du motif, des limites d’entrée et de la topologie. L’attaquant doit atteindre la correspondance vulnérable avec une entrée qui déclenche son chemin coûteux. Traitez cela comme un risque de disponibilité du processus concerné ; l’indisponibilité du service entier dépend des workers, réplicas, du routage et des contrôles de santé.
Cas réel npm : CVE-2026-83606 dans xmldom
L’avis examiné pour @xmldom/xmldom signale CWE-1333 dans l’analyse des instructions de traitement : la grammaire vulnérable permet à un groupe gourmand d’espaces et à un groupe paresseux de données de consommer les mêmes espaces. Sans le marqueur final ?>, l’analyseur essaie de nombreuses partitions et prend un temps quadratique. Les versions 0.9.0-beta.9 à 0.9.10 sont touchées ; 0.9.11 corrige le problème en empêchant le séparateur de rendre les espaces au groupe de données. L’avis limite le problème au chemin 0.9.x du paquet avec portée ; il ne désigne pas les versions 0.8.x ni le paquet sans portée.
L’audit des dépendances aide, sans prouver la sûreté des regex
npm audit rapporte les avis connus associés aux dépendances de l’arbre du projet ; il n’analyse pas toutes les regex du code et ne découvre pas les failles ReDoS non publiées. Maintenez les dépendances directes et transitives à jour, vérifiez les chemins d’appel touchés et inspectez séparément les motifs qui traitent des textes contrôlés par les utilisateurs.
npm audit --omit=dev
L’audit couvre les avis connus, pas tous les risques regex. Examinez le rapport selon votre déploiement et vérifiez séparément si une entrée non fiable peut atteindre une correspondance coûteuse et si sa taille est limitée.
Questions fréquentes
L’API RegExp ne propose pas de délai par correspondance. Préférez un motif simple et bornez l’entrée avant la comparaison. Si un traitement complexe est nécessaire, isolez-le dans un worker ou processus fils avec un délai d’arrêt applicable ; cela limite l’impact sans rendre le motif efficace.
Oui. Une correspondance synchrone pathologique peut figer le thread principal de la page jusqu’à son terme et bloquer l’interface. Bornez l’entrée, simplifiez le motif et évitez de le lancer à chaque frappe.
Traitez les motifs fournis par l’utilisateur comme une entrée exécutable pour un moteur potentiellement coûteux. N’acceptez pas de motifs arbitraires sur un serveur sans limites strictes et isolation. Si seule une recherche littérale est nécessaire, échappez l’entrée comme littéral regex ou utilisez les API de recherche textuelle ; l’échappement n’évite pas la limite de taille.