Mongoose es una biblioteca de modelado de datos orientada a objetos (ODM) para MongoDB que simplifica las interacciones con la base de datos en aplicaciones Node.js. Al ofrecer una solución basada en esquemas, Mongoose permite asignar objetos JavaScript a documentos de MongoDB, actuando como una capa de abstracción que ayuda a estructurar los datos para facilitar su gestión y validación. Con características como middleware para la ejecución de lógica personalizada y un sistema intuitivo de construcción de consultas, Mongoose mejora la eficiencia del trabajo con MongoDB. Mongoose, descrito como «un elegante modelado de objetos MongoDB para Node.js», ha obtenido 27 000 estrellas en GitHub, lo que refleja su uso generalizado y el reconocimiento entre los desarrolladores.
El programa OPSWAT y la detección de vulnerabilidades críticas
El Programa de Becas de Posgrado en Ciberseguridad de InfraestructurasOPSWAT , con sede en Vietnam, ofrece a los estudiantes de posgrado experiencia práctica en la protección de infraestructuras críticas. Como parte de este programa, los becarios tienen la oportunidad de analizar y resolver vulnerabilidades de ciberseguridad, colaborando con OPSWAT para hacer frente a retos reales en ámbitos como la detección de malware, la seguridad de archivos y la prevención de amenazas.
Durante el programa OPSWAT , los participantes investigan y reproducen de forma sistemática vulnerabilidades CVE conocidas en diversos productos, bibliotecas y sistemas operativos. Como parte de esta iniciativa, Dat Phung —uno de nuestros distinguidos becarios— decidió examinar Mongoose debido a su amplia adopción en entornos de producción. En noviembre de 2024, descubrió una vulnerabilidad crítica en Mongoose mientras realizaba un análisis en profundidad de la biblioteca. La vulnerabilidad permitía a un atacante explotar el valor $where, lo que podía dar lugar a la ejecución remota de código (RCE) en el servidor de aplicaciones Node.js. Tras informar rápidamente del problema a Mongoose, se publicó un parche como parte de la versión 8.8.3, y el CVE-2024-53900 se dio a conocer en la Base de Datos Nacional de Vulnerabilidades (NVD).
Cronología de CVE-2024-53900 y CVE-2025-23061
- 7 de noviembre de 2024: Dat Phung detectó una vulnerabilidad crítica en Mongoose y envió un informe de seguridad a Snyk.
- 26 de noviembre de 2024: Mongoose lanzó la versión 8.8.3 para abordar y corregir esta vulnerabilidad.
- 2 de diciembre de 2024: La Base de Datos Nacional de Vulnerabilidades (NVD) publicó el CVE-2024-53900 para esta vulnerabilidad.
- 17 de diciembre de 2024: Tras analizar el parche 8.8.3 de Mongoose, Dat Phung descubrió una vulnerabilidad que seguía permitiendo la ejecución remota de código (RCE). Se envió un informe de seguridad detallado a Tidelift.
- 13 de enero de 2025: Mongoose lanzó la versión 8.9.5, que incluía un parche mejorado que solucionaba de forma efectiva la vulnerabilidad.
- 15 de enero de 2025: La Base de Datos Nacional de Vulnerabilidades (NVD) dio a conocer oficialmente el CVE-2025-23061, haciendo hincapié en la gravedad de la vulnerabilidad recién identificada.
El método Populate() de Mongoose
Mongoose también ofrece una función muy útil llamada `populate()` que mejora la capacidad de trabajar con relaciones entre documentos. Aunque las versiones de MongoDB ≥ 3.2 cuentan con el operador de agregación `$lookup` para realizar uniones, la función `populate()` de Mongoose ofrece una alternativa más potente para sustituir automáticamente una referencia por los datos correspondientes de los documentos relacionados. Esto resulta especialmente útil para gestionar relaciones entre diferentes colecciones de MongoDB, como cuando un documento hace referencia a otro mediante su `_id`. [2]



Al definir un esquema en Mongoose, se puede configurar un campo para que haga referencia a otro modelo utilizando la opción `ref`. A continuación, se utiliza el método populate() para sustituir el campo al que se hace referencia (un ObjectId) por el documento completo del modelo relacionado. Por ejemplo, en una aplicación de librería, el campo author del bookSchema hace referencia al documento Author, y el campo review hace referencia al documento Reviews. El método populate() permite a los desarrolladores sustituir el campo author (que es un ObjectId) por el documento completo Author al consultar el modelo book.
El método `populate()` permite a los desarrolladores sustituir el campo «author» (que es un ObjectId) por el documento «Author» completo al consultar el modelo «book »:


Además, el método `populate()` de Mongoose admite consultas personalizadas para definir qué documentos relacionados se recuperan y cómo se obtienen. Propiedades como `match` y `options` permiten a los desarrolladores filtrar, ordenar, limitar y omitir documentos relacionados, lo que ofrece una gran flexibilidad a la hora de recuperar datos.

Análisis de CVE-2024-53900
En el marco del programa de becas de posgrado OPSWAT , mientras analizaba Mongoose para reproducir vulnerabilidades CVE conocidas, Dat Phung llevó a cabo un análisis exhaustivo del funcionamiento interno del método `populate()`, que desempeña un papel fundamental en la gestión de las relaciones entre los documentos de MongoDB. El método `populate()` admite tanto argumentos de tipo cadena como de tipo objeto, y los desarrolladores pueden utilizar la opción `match` para aplicar filtros específicos a los datos que se recuperan:

En el ejemplo anterior, la opción «match» es un objeto de filtro que puede incluir operadores de consulta de MongoDB, tal y como se detalla en «Operadores de consulta y proyección» del Manual de MongoDB v8.0. Un operador destacado es «$where», que permite la ejecución de JavaScript directamente en el servidor de MongoDB. Sin embargo, esta ejecución en el servidor de MongoDB está limitada, ya que solo admite operaciones y funciones básicas.

Dat Phung llevó a cabo un análisis en profundidad del código fuente de Mongoose para comprender el flujo de trabajo del método `populate()`. Determinó que, una vez que la aplicación invoca el método `populate()` en el modelo, se activa la función `populate()`. Dentro de esta función, Mongoose llama a la función _execPopulateQuery() , que ejecuta la consulta con el operador $where en el servidor de MongoDB. Posteriormente, se recuperan todos los documentos de la colección externa para su población en los siguientes pasos.

Tras recuperar los datos de MongoDB, Mongoose ejecuta la función de llamada de retorno _done(), que a su vez llama a _assign() para preparar los datos antes de «unir» los dos modelos mediante la función assignVals().

La vulnerabilidad puede surgir cuando los datos recuperados se procesan mediante la función `assignVals()` de Mongoose. Esta función comprueba si la opción `match` es una matriz y, en caso afirmativo, pasa cada operador a la función `sift()`. La función `sift()` , que se importa desde una biblioteca externa del mismo nombre, procesa estas consultas de forma local en el servidor de la aplicación. Este procesamiento local supone un riesgo de seguridad, especialmente al gestionar entradas controladas por el usuario.

Para profundizar en el análisis, Dat Phung modificó los valores de la opción «match» con el fin de garantizar que se cumplieran las condiciones, lo que provocó la ejecución de la función «sift()» para realizar un análisis más detallado del flujo de datos.

Una vez establecida la condición, el operador $where se pasó a continuación a la función sift().

La biblioteca sift es una utilidad ligera de JavaScript diseñada para filtrar y consultar conjuntos de datos, como matrices u objetos JSON, utilizando una sintaxis similar a la de MongoDB. Según la documentación oficial, «Sift es una pequeña biblioteca que permite utilizar consultas de MongoDB en JavaScript». La función sift() evalúa operaciones de filtrado similares a las de MongoDB en el servidor de la aplicación en lugar de en el servidor de la base de datos, lo que puede exponer al sistema a importantes riesgos de seguridad al procesar entradas no fiables.

Continuando con su análisis, nuestro becario detectó un problema en la función `createDefaultQueryTester() ` de la biblioteca `sift`. Esta función convierte cada operación del array `match` en funciones JavaScript ejecutables, que luego se utilizan para filtrar y procesar los datos de los documentos de MongoDB de forma local. Para ello, `createDefaultQueryTester()` invoca la función `createNamedOperation()`, pasando como argumentos operaciones como `$where` del array `match`.

Para cada operación de la matriz de coincidencias, createNamedOperation comprueba si la operación es compatible y, a continuación, la pasa a la función correspondiente.

Si la operación es $where, se genera una función JavaScript utilizando el valor sin procesar «params», que se deriva del operador $where en la matriz de coincidencias y puede ser controlado por el usuario.

CVE-2024-53900: Detalles de la vulnerabilidad
Aunque MongoDB limita la ejecución de funciones JavaScript a través de la operación $where, tal y como se ha analizado anteriormente, la función sift() permite ejecutar estas funciones sin tales restricciones. Esta falta de validación y restricción de las entradas supone una importante vulnerabilidad de seguridad, ya que el valor «params» —controlado directamente por la entrada del usuario— puede ser objeto de abuso, lo que podría dar lugar a ataques de inyección de código. Para examinar este problema con mayor detalle, Dat Phung elaboró la siguiente consulta:

Al principio, la consulta no pudo ejecutar otro proceso, lo que provocó el siguiente error:

Este error indica que Mongoose intenta ejecutar la operación $where en el servidor de MongoDB antes de pasar el control a la función sift(). Sin embargo, debido a las restricciones que se aplican a las funciones de JavaScript en la cláusula $where de MongoDB, se produce un error que impide que se ejecute la consulta. Como consecuencia, Mongoose detiene el proceso antes de que pueda llegar a la función sift() .
Para sortear esta limitación, nuestro compañero aprovechó la variable «global» presente en el servidor de aplicaciones, que no existe en el servidor de MongoDB. Este enfoque le permitió eludir la restricción del servidor de MongoDB y hacer que la consulta llegara a la función sift():

Con este valor, cuando Mongoose ejecuta la operación $where en MongoDB, la ausencia de la variable «global» hace que el operador ternario (typeof global != "undefined" ?global.process.mainModule.constructor._load("child_process").exec("calc") : 1)devuelva 1, lo que evita que MongoDB genere un error. En consecuencia, la consulta se ejecuta en el servidor de MongoDB sin problemas.
Sin embargo, cuando ese mismo valor llega a la función `sift()`, que se ejecuta en el servidor de aplicaciones donde está disponible la variable «global», se activa la creación de la siguiente función:

Prueba de concepto de ejecución remota de código (RCE)
En el ejemplo de aplicación que se ofrece al principio del blog, si un atacante enviara la siguiente solicitud, podría llevar a cabo con éxito un ataque de ejecución remota de código (RCE):


El vídeo muestra la demostración de concepto de la vulnerabilidad CVE-2024-53900, que afecta a las versiones de Mongoose anteriores a la 8.8.3, las cuales carecen de una validación adecuada de las entradas para evitar el uso indebido del operador $where junto con la biblioteca sift.
Solución incompleta y CVE-2025-23061
A raíz del informe de seguridad de Dat Phung, Mongoose lanzó un parche destinado a resolver la vulnerabilidad identificada anteriormente (CVE-2024-53900) antes de que se hiciera pública. El parche en cuestión (Automattic/mongoose@33679bc) añadió una comprobación para impedir el uso de $where dentro de la propiedad match pasada a la función populate().

Este fragmento de código comprueba si la propiedad «match» pasada a la función «populate()» es una matriz. Si lo es, el código recorre cada objeto de la matriz para comprobar si contiene el operador «$where ». Si se detecta «$where», se genera un error, lo que impide que la carga maliciosa se propague a la función «sift()», que supone un riesgo.
En consecuencia, la carga útil que aprovecha la vulnerabilidad CVE-2024-53900 no supera esta comprobación porque un objeto de la matriz «match» contiene «$where», lo que impide que llegue a la función «sift()».

Aunque esta actualización bloquea correctamente el uso directo de $where dentro de un único nivel de anidamiento, no detecta $where cuando se incluye dentro de un operador $or, una estructura que tanto MongoDB como la biblioteca sift admiten plenamente.


Como consecuencia, un atacante puede anidar $where dentro de $or para eludir la comprobación de un solo nivel del parche. Dado que Mongoose solo inspecciona las propiedades de primer nivel de cada objeto del array «match», la carga útil de elusión pasa desapercibida y acaba llegando a la biblioteca «sift», lo que permite la ejecución remota de código maliciosa.

Demostración de concepto para CVE-2025-23061
Para ilustrar el carácter incompleto de la corrección, Dat Phung volvió a compilar la aplicación de ejemplo utilizando una versión de Mongoose 8.9.4 (posterior a la 8.8.3). Al anidar $wheredentro de una cláusula $or, un atacante puede eludir con éxito la comprobación y lograr la ejecución de código remoto (RCE).
El exploit de prueba de concepto muestra cómo se puede aprovechar la vulnerabilidad CVE-2025-23061 en versiones de Mongoose anteriores a la 8.9.5, lo que permite a un atacante ejecutar código arbitrario en el servidor:
Medidas de mitigación y orientación
Para mitigar las vulnerabilidades que hemos comentado anteriormente, asegúrese de que su sistema esté actualizado a la última versión de Mongoose.
MetaDefender Core su motor SBOM, puede detectar esta vulnerabilidad
OPSWAT MetaDefender Core, equipado con capacidades avanzadas de SBOM (Software de materialesSoftware ), permite a las organizaciones adoptar un enfoque proactivo a la hora de abordar los riesgos de seguridad. Al analizar las aplicaciones de software y sus dependencias, MetaDefender Core vulnerabilidades conocidas, como CVE-2024-53900 y CVE-2025-23061, dentro de los componentes enumerados. Esto permite a los equipos de desarrollo y seguridad priorizar las tareas de aplicación de parches, mitigando los posibles riesgos de seguridad antes de que puedan ser explotados por actores maliciosos.
A continuación se muestra una captura de pantalla de CVE-2024-53900 y CVE-2025-23061, que fueron detectadas por MetaDefender Core SBOM:

Además, las vulnerabilidades CVE también pueden detectarse mediante MetaDefender Software Supply Chain, que aprovecha MetaDefender Core SBOM para identificar estas vulnerabilidades.


