Las 10 principales vulnerabilidades de seguridad de JavaScript
JavaScript impulsa una gran cantidad de aplicaciones modernas, desde frontends web dinámicos hasta backends escalables con Node.js, lo que significa que también expone una amplia superficie de ataque. La flexibilidad que hace que JavaScript sea tan potente puede convertirse en un arma de doble filo si se pasa por alto la seguridad. El código frontend se ejecuta directamente en los navegadores de los usuarios (y puede ser inspeccionado o manipulado por atacantes), mientras que las aplicaciones backend de Node.js a menudo integran innumerables paquetes y manejan datos sensibles. La cruda realidad es que una sola línea de JavaScript insegura o una dependencia vulnerable puede abrir la puerta a exploits. De hecho, informes recientes de la industria muestran que las aplicaciones web siguen plagadas de vulnerabilidades comunes como cross-site scripting y librerías desactualizadas, a pesar de años de advertencias.
Cada script etiqueta, cada npm install, y cada análisis JSON podría ocultar un riesgo potencial. En las secciones siguientes, desglosamos las diez principales vulnerabilidades de seguridad de JavaScript (que abarcan problemas tanto del lado del cliente como del lado del servidor), con ejemplos reales y consejos sobre cómo solucionarlas o prevenirlas. Desde trampas clásicas como XSS hasta las más avanzadas ataques a la cadena de suministro, cada vulnerabilidad incluye pasos de mitigación y una mención sobre cómo las herramientas de seguridad modernas (como Aikido’s SAST, detección de secretos, y análisis de dependencias) pueden ayudar a detectar problemas a tiempo.
1. Ataques de cross-site scripting (XSS)
Cross-Site Scripting (XSS) is one of the most prevalent vulnerabilities in we11b applications year after year. XSS occurs when an application includes unsanitized user input in a webpage, allowing attackers to inject malicious JavaScript that executes in the browsers of other users. This can lead to session hijacking, defacement, and theft of sensitive data. Even widely used libraries have suffered XSS flaws – for example, a five-year-old jQuery bug (CVE-2020-11023) allowed arbitrary code execution by passing malicious HTML to jQuery’s DOM methods. Unsuspecting developers who included a vulnerable jQuery (<3.5.0) version in their frontend exposed their users to potential XSS, a flaw so serious that U.S. CISA added it to its exploited vulnerabilities catalog in 2025.
Ejemplo real: Un atacante podría crear un comentario o nombre de perfil que contenga <script> etiquetas en un foro que no escapa correctamente la salida. Cuando otros usuarios ven esa página, el script se ejecuta en su navegador, quizás robando su cookie de sesión o suplantando su identidad. el informe de seguridad de Claranet de 2024 encontrado 2.570 instancias de XSS (reflejado y almacenado) en 500 pruebas de penetración, lo que lo convierte en “una de las vulnerabilidades más comunes encontradas… en los últimos cinco años”. Esto subraya que XSS sigue siendo una amenaza principal en aplicaciones con mucho JavaScript.
Mitigación: Defenderse contra XSS requiere una combinación de prácticas de codificación y defensas del navegador:
- Escape y valide la salida: Nunca inyecte entrada de usuario sin procesar en HTML. Sanee la entrada al recibirla y escape la salida en el contexto adecuado (HTML, atributo, JavaScript, etc.).
- Utiliza los controles del framework: Aprovecha los frameworks de plantillas o de frontend (React, Angular, Vue) que escapan o sanean automáticamente el contenido. Evita usar sumideros peligrosos como
innerHTMLodocument.writecon datos dinámicos – utiliza alternativas más seguras comotextContent. - Content Security Policy (CSP): Implementa una cabecera CSP estricta para restringir de dónde se pueden cargar los scripts. CSP puede actuar como una segunda línea de defensa al bloquear scripts no autorizados.
- Cookies HttpOnly y SameSite: Marca las cookies como HttpOnly (no accesibles vía JS) y utiliza
SameSiteatributos para dificultar algunos tipos de ataques (como el robo de cookies por cross-site scripting o CSRF).
Detectar XSS requiere vigilancia en la revisión y las pruebas de código. Las pruebas de seguridad de aplicaciones estáticas (SAST) de Aikido pueden señalar patrones peligrosos, por ejemplo, el uso de innerHTML con datos proporcionados por el usuario o la falta de codificación de salida en las plantillas del servidor. El análisis de dependencias también ayuda: Aikido te alertaría si estás utilizando una versión antigua de una librería conocida por habilitar XSS (como el ejemplo de jQuery 3.4.1 anterior) para que puedas actualizar a una versión parcheada. Al integrar escaneos automatizados en tu CI/CD, puedes detectar vulnerabilidades XSS a tiempo, antes de que lo hagan los atacantes.
2. Contaminación de Prototipos
La contaminación de prototipos es una vulnerabilidad específica de JavaScript que aprovecha la naturaleza dinámica de los prototipos de objetos. En JavaScript, los objetos heredan propiedades de su prototipo, y si un atacante puede inyectar propiedades en Object.prototype, esas propiedades se vuelven accesibles en todos los objetos – lo que a menudo lleva a una denegación de servicio o incluso a la ejecución remota de código. Muchas librerías populares han sufrido CVEs de contaminación de prototipos. Por ejemplo, las versiones de Lodash anteriores a la 4.17.12 tenían una vulnerabilidad en su defaultsDeep y otras funciones que podrían ser engañadas para modificar Object.prototype via a crafted payload. Another example is Handlebars.js: versions <4.3.0 allowed template input to alter special properties like __proto__, que “puede permitir a un atacante ejecutar código arbitrario” en el servidor (CVE-2019-19919).
Ejemplo real: Un atacante envía datos JSON a una API con una carga útil como {"__proto__": {"admin": true}}. Si la aplicación fusiona objetos sin protección (por ejemplo, utilizando un obsoleto lodash.merge o similar), la cadena de prototipos se contamina, y posteriormente, comprobaciones como if(user.admin) podría devolver inesperadamente 'true' para todos los usuarios, o peor aún, la lógica de la aplicación podría ser subvertida. En algunos casos, la contaminación de prototipos puede combinarse con otras técnicas para ejecutar código. Por ejemplo, la vulnerabilidad de “prototype poison” en las plantillas de Handlebars mencionada anteriormente podría utilizarse para ejecutar JavaScript del lado del servidor en el contexto de la aplicación.
Mitigación: Para prevenir la contaminación de prototipos:
- Actualizar dependencias: Utiliza versiones fijas de librerías que hayan corregido errores de contaminación de prototipos. Por ejemplo, actualiza Lodash a >=4.17.20 (que corrigió múltiples CVE de este tipo).
- Validación de entrada: Valida y sanea las entradas JSON o de objetos. Rechaza o filtra las claves de objeto llamadas
__proto__,constructor, o prototipos en los datos. - Fusión Segura de Objetos: Al fusionar objetos (por ejemplo, clonación profunda o extensión), utiliza funciones o librerías seguras que no copien propiedades de prototipo. Algunas librerías de utilidad ofrecen opciones para ignorar propiedades heredadas.
- Ejecutar en Modo Estricto: Aunque no es una solución milagrosa, el modo estricto (
"use strict") puede prevenir ciertas acciones peligrosas y facilitar la detección de errores.
La contaminación de prototipos puede ser sutil, pero el análisis de dependencias es tu aliado aquí. El escáner de dependencias de Aikido señalará las versiones vulnerables conocidas de librerías como Lodash, jQuery o Handlebars que son susceptibles a la contaminación de prototipos, para que puedas actualizarlas de forma proactiva. En cuanto al código, el motor SAST de Aikido puede detectar patrones de fusión de objetos insegura o el uso de claves de objeto potencialmente peligrosas. Al usar Aikido para auditar continuamente tanto tu código como tus paquetes npm, obtienes una red de seguridad para esta clase de errores, detectándolos durante el desarrollo en lugar de después de una brecha.
3. Deserialización Insegura
Los fallos de deserialización insegura ocurren cuando una aplicación acepta datos serializados no confiables y los deserializa en objetos sin una validación adecuada. En JavaScript/Node, esto a menudo implica funciones que toman objetos JSON o JavaScript proporcionados por el usuario y los "reviven" en objetos activos. Si no se maneja con cuidado, la deserialización puede ser abusada para ejecutar código arbitrario o manipular el estado de la aplicación. Un ejemplo notorio fue la node-serialize vulnerabilidad del paquete (CVE-2017-5941): permitía a los atacantes pasar un objeto serializado malicioso que contenía una Expresión de Función Invocada Inmediatamente (IIFE). Tras la deserialización, la función se ejecutaría en el servidor, logrando efectivamente la ejecución remota de código.
Ejemplos reales: Este problema no es teórico; incluso los principales frameworks lo han gestionado mal. A finales de 2025, se reveló una vulnerabilidad crítica de React/Next.js (denominada React2Shell, CVE-2025-55182), originada en cómo los React Server Components manejan los datos serializados. «En el centro del problema está la deserialización insegura», señaló la investigación de Akamai, que permitió a los atacantes inyectar claves de objeto maliciosas, lo que llevó a la contaminación de prototipos y, en última instancia, a la ejecución remota de código en el servidor. Esto significa que, al enviar una solicitud HTTP especialmente diseñada, un atacante no autenticado podría tomar el control de un servidor Node.js que ejecute código React vulnerable, un escenario de pesadilla para cualquier equipo DevSecOps.
Mitigación: Prevenir la deserialización insegura implica un manejo cuidadoso de los formatos de datos:
- Prefiere formatos seguros: Utiliza JSON para el intercambio de datos y evita analizar código o funciones de JavaScript de la entrada del cliente. JSON.parse estándar es más seguro que
eval()o la deserialización personalizada de objetos JS. - Listas blancas y validación: Si debes aceptar objetos serializados, implementa esquemas estrictos o listas blancas. Solo permite las propiedades y tipos de objetos esperados. Rechaza cualquier entrada que contenga claves como
__proto__o constructor que podrían ser vectores de abuso. - Evita
evalyFunction(): No useseval()en JSON o aceptar código JS sin procesar de los clientes. De manera similar, evita las librerías que ejecutan datos de objetos (por ejemplo, evita ejecutar automáticamente funciones que provienen de entradas analizadas). - Actualizaciones de librerías: Mantente al día con los parches del framework. La vulnerabilidad de React mencionada anteriormente se solucionó con actualizaciones de React/Next; aplica dichos parches inmediatamente y monitoriza los avisos de las librerías de Node.js que realizan deserialización.
La plataforma de Aikido puede ayudar a detectar la deserialización insegura de varias maneras. análisis estático de código le advertirá si su código está utilizando funciones de riesgo (como unserialize() de una librería desactualizada o utilizando eval en la entrada). Si está utilizando paquetes conocidos con vulnerabilidades (como el defectuoso node-serialize <=0.0.4, or certain versions of React), Aikido’s dependency scanner would flag those by CVE. Additionally, Aikido’s runtime SAST analysis (if integrated in testing) can observe data flows – for example, user input flowing into a dangerous sink – and alert you. The bottom line: integrating such tools in CI means you’d catch something like React2Shell in your code antes de se convierte en React2Shell en las noticias.
4. Falsificación de Peticiones en Sitios Cruzados (CSRF)
La Falsificación de Peticiones en Sitios Cruzados (CSRF) es una vulnerabilidad web clásica que a menudo afecta a aplicaciones basadas en JavaScript (o cualquier aplicación web con sesiones). A diferencia de XSS, que explota la inyección de código, CSRF explota la confianza en el navegador del usuario. Permite a un atacante engañar al navegador de una víctima para que realice peticiones no intencionadas a su aplicación, bajo la apariencia de las propias credenciales de la víctima. En términos más sencillos, si un usuario ha iniciado sesión en su sitio, un atacante puede inducir potencialmente a su navegador (a través de un enlace o imagen maliciosa) a realizar acciones como cambiar detalles de la cuenta o iniciar transacciones sin el consentimiento del usuario.
Ejemplo real: Un ejemplo bien conocido es el analogía de la publicación en el foro/transferencia bancaria – imagina una aplicación bancaria donde el formulario de transferencia de dinero es vulnerable a CSRF. Un atacante podría enviar un enlace a un usuario autenticado (o incrustar un formulario de envío automático en una página maliciosa) que active POST /transfer?amount=1000&to=attackerAccount. Si la aplicación bancaria no tiene protección CSRF, el navegador del usuario enviará diligentemente esa solicitud junto con las cookies de sesión, y el banco la ejecutará pensando que el usuario la ha iniciado. En el contexto de JavaScript, las Single Page Applications (SPAs) pueden depender de APIs que utilizan cookies para la autenticación; si esas APIs no implementan defensas CSRF (como requerir un token o cookies same-site), son igualmente explotables. Incluso los frameworks que incluyen tokens CSRF pueden estar mal configurados; por ejemplo, si el backend de una aplicación Angular o React establece una política CORS demasiado amplia o faltan flags de SameSite, los ataques CSRF pueden pasar desapercibidos.
Mitigación: Las estrategias clave para detener el CSRF incluyen:
- Tokens CSRF: Incrusta tokens impredecibles en formularios o llamadas a la API y verifícalos en el lado del servidor. Los frameworks modernos suelen tener middleware CSRF. Asegúrate de que los tokens estén vinculados a la sesión del usuario y se verifiquen en cada solicitud que cambie el estado.
- Cookies SameSite: Configura las cookies de sesión con el
SameSite=LaxoStrictatributo. Esto restringe a los navegadores el envío de cookies en solicitudes entre sitios (el mecanismo principal de CSRF). Cabe destacar que,Strictpodrían romper algunos flujos legítimos, por lo queLaxes una configuración predeterminada equilibrada para la mayoría de las aplicaciones. - Cabeceras Personalizadas y Verificación de Origen: Para las API (especialmente si se usa fetch/XHR en SPAs), puedes requerir una cabecera personalizada (por ejemplo,
X-Requested-With: XMLHttpRequest) y rechazar las solicitudes que no la tengan. Además, comprueba lasOriginyReferercabeceras en solicitudes sensibles – asegúrate de que provengan de tu dominio. - Evita usar GET para cambios de estado: CSRF puede usar
<img>o<script>etiquetas para iniciar solicitudes GET. Asegúrate de que cualquier acción crítica (como modificar datos) use POST (u otros métodos que no sean GET), e idealmente que siga requiriendo un token.
Aunque CSRF se relaciona más con el diseño que con un error de código, el kit de herramientas de seguridad de Aikido puede seguir siendo de ayuda. Análisis estático puede detectar rutas o controladores que carecen de protecciones CSRF si estás utilizando frameworks comunes (por ejemplo, una falta de csrf() middleware en una aplicación Express, o ningún módulo anti-CSRF en uso). Aikido también puede escanear tus encabezados de seguridad HTTP y configuraciones de cookies (mediante análisis dinámico o scripts de pipeline) para señalar la falta de SameSite o HttpOnly atributos. Al integrar estas comprobaciones, Aikido garantiza que los hábitos de codificación segura (como la implementación de tokens CSRF y flags de cookies adecuados) se apliquen de forma consistente en todo su proyecto.
5. Inyección NoSQL
Así como las bases de datos SQL tradicionales sufren de inyección SQL, las aplicaciones JavaScript modernas que utilizan bases de datos NoSQL (como MongoDB, CouchDB, etc.) pueden ser vulnerables a la inyección NoSQL. La inyección NoSQL ocurre cuando un atacante manipula entradas que se utilizan en consultas NoSQL, permitiéndoles alterar consultas, eludir la autenticación o recuperar datos no autorizados. Dado que las consultas NoSQL a menudo utilizan JSON u objetos de consulta, la sintaxis es diferente a la de SQL, pero el concepto de inyectar parámetros de formas inesperadas sigue siendo aplicable.
Ejemplo real: Considere una aplicación Node.js que utiliza MongoDB para la autenticación de usuarios, con un código como el siguiente:
// insecure pseudo-codeUsers.findOne({ username: inputUser, password: inputPass })
Esto parece correcto a primera vista, pero las consultas de MongoDB aceptan objetos y operadores especiales. Un atacante podría enviar una carga útil JSON para inputPass como { "$ne": null }. La consulta se convierte en {username: "victim", password: { $ne: null } }, lo que en Mongo significa “encontrar un usuario con nombre de usuario ‘victim’ y una contraseña que no sea nula” – esencialmente eludiendo la verificación de la contraseña porque $ne: null es siempre verdadero para un campo de contraseña real. Este tipo de inyección de operadores NoSQL es una técnica conocida para eludir formularios de inicio de sesión. La Web Security Academy de PortSwigger documenta cómo la inyección NoSQL puede “permitir a un atacante eludir la autenticación, extraer o alterar datos, o incluso ejecutar código en el servidor” en algunos casos.
Más allá de la elusión de autenticación, la inyección NoSQL puede usarse para extraer datos. Por ejemplo, inyectando $regex u otros operadores, los atacantes podrían enumerar registros de usuarios o volcar bases de datos si la aplicación no es cuidadosa.
Mitigación:
- Saneamiento de Entradas: No pases datos controlados por el usuario directamente a las consultas de la base de datos. Sanea las entradas – por ejemplo, si esperas un nombre de usuario de tipo cadena, asegúrate de que sea una cadena y no contenga
$u otros caracteres especiales. Algunos ORM o librerías de controladores tienen comprobaciones o modos integrados para prevenir la inyección de operadores (por ejemplo, Mongoose puede deshabilitar$claves prefijadas por defecto). - Usa Consultas Parametrizadas / ORM: Usar un ORM o un constructor de consultas puede reducir la exposición directa a consultas sin procesar. Asegúrate de utilizar cualquier característica de parametrización disponible.
- Autenticación y Lógica de Consulta: No dependas de una sola condición para operaciones sensibles. Para el inicio de sesión, prefiere un flujo de trabajo que verifique la contraseña de forma independiente (después de recuperar el usuario por nombre de usuario) en lugar de una gran consulta que podría ser manipulada.
- Registro y Monitorización: Los intentos de inyección NoSQL a menudo dejan rastros (por ejemplo, patrones de consulta extraños o errores). Registra los intentos de inicio de sesión fallidos y los parámetros de consulta inesperados; podría ayudar a detectar un ataque en curso.
El análisis estático de Aikido puede detectar patrones de riesgo como el uso de
findOne()
o consultas similares con entrada de usuario sin verificar. Por ejemplo, Aikido podría señalar si detecta $ o caracteres regex concatenados en una cadena de consulta, o el uso de Users.findOne({ ... entrada de usuario ... }) sin sanitización. Además, el escaneo dinámico de Aikido (si lo empleas contra una instancia de desarrollo en ejecución) puede incluir pruebas específicas para la inyección NoSQL, de manera similar a cómo las herramientas DAST prueban la inyección SQLi. Al aprovechar estas herramientas, los desarrolladores reciben una advertencia temprana: «Oye, esta función de inicio de sesión podría ser vulnerable a una inyección NoSQL». Solucionarlo a tiempo te evita un bypass de autenticación potencialmente desastroso en producción.
6. Denegación de Servicio por Expresiones Regulares (ReDoS)
La Denegación de Servicio por Expresiones Regulares (ReDoS) es una vulnerabilidad en la que un atacante proporciona una entrada especialmente diseñada a una regex (expresión regular) que tarda un tiempo excepcionalmente largo en evaluarse, monopolizando la CPU y causando efectivamente una denegación de servicio. El motor de regex de JavaScript (como muchos otros) puede exhibir retroceso catastrófico en ciertos patrones. Esto es particularmente relevante para Node.js, donde un solo hilo maneja muchos clientes; una regex atascada puede bloquear todo el bucle de eventos. Se han encontrado vulnerabilidades ReDoS en varios paquetes y frameworks de npm. Por ejemplo, se descubrió un fallo de baja gravedad pero notable en el compilador de plantillas de Vue.js 2 (CVE-2024-9506): una regex mal escrita para analizar HTML podría ser explotada por un <textarea> o <script> etiqueta a “causar retrasos significativos en el análisis de plantillas”. De manera similar, el popular path-to-regexp librería (utilizada en el enrutamiento de Express) tuvo un problema de ReDoS (CVE-2024-52798), y un sinfín de librerías de validación (para URLs, correos electrónicos, etc.) han tenido CVEs de ReDoS a lo largo de los años.
Ejemplo real: Imagine un servidor Node.js que utiliza una expresión regular para validar direcciones de correo electrónico en el registro de usuarios. Un patrón de expresión regular ingenuo (por ejemplo, algo como /(.+)@(.+)\.(.+)/) podría retroceder catastróficamente en una cadena de cierta longitud y composición. Los atacantes podrían enviar una cadena de correo electrónico extremadamente larga como "aaaa....aaaa!" (con ciertos patrones) que hace que la expresión regular se atasque durante segundos o más, tiempo durante el cual el servidor podría no manejar otras solicitudes. En un caso, un ReDoS en la validator.js se encontró una validación de URL de la librería; una entrada de URL manipulada de unas pocas docenas de kilobytes hizo que el proceso se colgara. Si un atacante automatizara el envío masivo de tales entradas, podría efectivamente derribar el servicio. La fundación OWASP señala que la mayoría de los motores de expresiones regulares son susceptibles a este tipo de casos extremos.
Mitigación:
- Evita expresiones regulares complejas para entradas no confiables: Simplifica tus patrones de regex o utiliza enfoques sin retroceso. Si es posible, usa librerías integradas o algoritmos validados para tareas comunes (por ejemplo, utiliza el analizador de URL integrado de Node en lugar de una regex compleja para URLs).
- Utiliza tiempos de espera: Para casos críticos, puedes usar una librería de regex que soporte tiempos de espera o sandboxing. En Node, el
RegExplas operaciones son síncronas, pero podrías ejecutar el trabajo de regex en un hilo de trabajador separado si fuera necesario para evitar bloquear el bucle principal. - Limita la longitud de la entrada: A menudo, ReDoS se basa en cadenas de entrada muy grandes. Al imponer límites de longitud razonables en las entradas (por ejemplo, ninguna dirección de correo electrónico debería superar los 254 caracteres según la RFC), reduces la viabilidad de ReDoS.
- Revisa y prueba los patrones: Existen herramientas que pueden analizar expresiones regulares en busca de un potencial de retroceso catastrófico. Incorpóralas en la revisión de código para cualquier patrón complejo. Escribe casos de prueba con entradas patológicas para ver cómo se comportan tus expresiones regulares bajo estrés.
El análisis de dependencias destaca aquí – Aikido rastrea CVEs y debilidades conocidas en tus paquetes npm. Si estás utilizando un paquete con un ReDoS conocido (por ejemplo, una versión vulnerable de un analizador de fechas o un validador de URL), Aikido te alertará para que actualices a una versión corregida. Para patrones de regex personalizados en tu código, el SAST de Aikido puede detectar literales de regex codificados o new RegExp() uso y aplicar verificaciones heurísticas (por ejemplo, marcando patrones con cuantificadores excesivos o grupos anidados). Puede que no detecte todas las regex maliciosas, pero combinado con la base de conocimientos de Aikido, puede advertir “Esta regex parece sospechosamente exponencial.” Además, las herramientas de prueba de Aikido pueden simular ataques de fuzzing; si una carga útil simple causa problemas de rendimiento, lo sabrías durante las pruebas en lugar de por un localizador a las 2 AM.
7. Recorrido de directorios y exposición de archivos
Las vulnerabilidades de Directory traversal (o path traversal) permiten a los atacantes acceder a archivos en el servidor que deberían estar restringidos, manipulando las rutas de los archivos. En Node.js, esto suele ocurrir con librerías o código que sirven archivos estáticos, gestionan descargas de archivos o procesan archivos zip. Si la entrada del usuario se concatena en las rutas de los archivos sin una sanitización adecuada, un atacante puede usar secuencias como ../ para salir del directorio previsto. Por ejemplo, se descubrió una vulnerabilidad en el node-static paquete (un servidor de archivos estáticos simple) se descubrió que una comprobación incorrecta en la servePath función permitía a un atacante solicitar una URL con .. y acceder a archivos arbitrarios (CVE-2023-26111). Una prueba de concepto demostró que un atacante podía recuperar archivos sensibles como /root/.ssh/id_rsa codificando ../../../../../ en la URL.
Ejemplo real: Un escenario común es una aplicación Express que utiliza express.static() o una ruta de servicio de archivos personalizada. Supongamos que tienes:
app.get('/download', (req, res) => { const file = req.query.file; res.sendFile(__dirname + '/uploads/' + file);});
Si no se tiene cuidado, un atacante puede llamar a /download?file=../../etc/passwd y recuperar archivos del sistema. Ha habido casos en los que las aplicaciones expusieron inadvertidamente claves o archivos de configuración de esta manera. Incluso al usar bibliotecas, ha habido errores: versiones antiguas del middleware estático de Express tenían problemas conocidos de directory traversal en casos límite (como URLs con puntos codificados). El manejo de rutas del núcleo de Node en Windows también tenía una peculiaridad de traversal (CVE-2025-27210) que involucraba nombres de dispositivos que podían ser abusados. Más allá de la lectura de archivos, la escritura de archivos es otro ángulo (por ejemplo, ataques de “Zip Slip” donde la extracción de un archivo zip escribe archivos fuera de la carpeta prevista).
Mitigación:
- Normalizar y validar rutas: Utiliza
path.normalize()ypath.join()para resolver cualquier..secuencias, y luego asegúrate de que la ruta resuelta esté dentro del directorio permitido. Por ejemplo, después de resolver, rechaza la solicitud si el archivo está fuera de tu/uploadscarpeta. - Evita Rutas Controladas Directamente por el Usuario: Siempre que sea posible, no utilices directamente la entrada del usuario como nombres de archivo. Mapea las entradas del usuario a rutas de archivo predefinidas. Por ejemplo, si los usuarios solo deben descargar sus propios archivos, utiliza un identificador y busca el nombre del archivo en el lado del servidor en lugar de confiar en un parámetro de nombre de archivo.
- Principio de Mínimo Privilegio: Ejecuta tus procesos Node.js con privilegios mínimos. Si la aplicación no tiene motivos para acceder fuera de ciertos directorios, considera restricciones a nivel de sistema operativo o la contenerización para limitar el daño que podría causar una vulnerabilidad de recorrido de directorios.
- Mantén las Librerías Actualizadas: Si utilizas librerías para servir archivos o para descomprimir, mantente al día con sus parches de seguridad. El
node-staticla vulnerabilidad mencionada no tenía “solución” en el paquete antiguo, lo que podría significar usar una librería alternativa o añadir tu propio parche.
El escaneo de Aikido puede detectar patrones comunes de directory traversal en el código. Por ejemplo, el uso de sendFile o readFile con req.query o req.params es una señal de alerta que nuestras reglas SAST pueden destacar. Aikido también hace referencias cruzadas de vulnerabilidades conocidas; si tu proyecto depende de una versión de send o node-static con un CVE para path traversal, te pedirá que actualices. Para los equipos de DevSecOps, la fortaleza de Aikido reside en combinar estas señales: imagina que marca tu fragmento de código de servicio de archivos como arriesgado y observa que estás utilizando una librería desactualizada para ello; esa información puede impulsar una remediación rápida (sanear la entrada y actualizar la versión de la librería). Esencialmente, Aikido actúa como un revisor de seguridad adicional, revisando tu lógica de acceso a archivos para que los atacantes no puedan rastrear tu sistema de archivos.
8. Dependencias Vulnerables y Desactualizadas
Las aplicaciones JavaScript modernas a menudo incluyen decenas o cientos de paquetes npm. Cada una de esas dependencias (y sus subdependencias) podría albergar vulnerabilidades conocidas. El uso de librerías desactualizadas es tan común que constituye su propia categoría de riesgo: versiones inseguras de frameworks frontend, módulos de Node o librerías de utilidad pueden exponer tu aplicación a ataques incluso si tu propio código está bien. El estudio de Claranet de 2024 encontró 1.032 instancias de librerías JavaScript desactualizadas en 500 aplicaciones, señalando que “el uso de JavaScript desactualizado puede llevar a XSS, ataques de Denegación de Servicio y divulgación de información sensible”. En otras palabras, los CVEs conocidos en librerías populares se traducen directamente en riesgos para tu aplicación si no las has actualizado.
Ejemplos reales:
- Lodash: Librería de utilidad extremadamente popular. Múltiples CVEs (como se discutió anteriormente) han afectado a Lodash: fallos de contaminación de prototipos (CVE-2018-16487, CVE-2019-10744, CVE-2020-8203) e incluso un problema de Denegación de Servicio por Expresión Regular en
_.escapeRegExp. Las aplicaciones que utilizaban versiones antiguas de Lodash heredaron esas vulnerabilidades. - jQuery: Once ubiquitous on the frontend. jQuery <3.5.0 had that XSS vulnerability where injecting
<option>las etiquetas podrían ejecutar scripts. Si su frontend todavía utiliza, por ejemplo, jQuery 2.1 o 3.4, está arrastrando vulnerabilidades XSS conocidas que los atacantes están explotando activamente. - Express y otros: El framework Express en sí ha tenido algunos CVEs (redirecciones abiertas, una denegación de servicio a través de solicitudes malformadas, etc.). Paquetes más pequeños como
moment(biblioteca de fechas) tuvo una vulnerabilidad de path traversal en ciertos usos (CVE-2022-24785),markdown-ittuvo un problema de XSS, y así sucesivamente. Incluso el núcleo de Node tuvo vulnerabilidades que requerían parches (como los problemas de contrabando de solicitudes HTTP y path traversal en 2022-2025).
El uso de componentes vulnerables es uno de los OWASP Top Ten (Bajo «Uso de componentes con vulnerabilidades conocidas»). Es esencialmente una preocupación de la cadena de suministro: si incorporas una librería, también incorporas sus fallos.
Mitigación:
- Análisis de dependencias y Actualizaciones: Ejecuta regularmente
npm audito herramientas similares para obtener una lista de vulnerabilidades conocidas en tus dependencias. Actualiza los paquetes a versiones parcheadas. Utiliza herramientas que te alerten cuando se encuentren nuevas vulnerabilidades en las librerías que utilizas. - Higiene del Lockfile: Mantén tu
package-lock.json(o lockfile de Yarn) cuidadosamente. Evita tener problemas de dependencias anidadas no resueltas utilizandonpm audit fixcuando sea apropiado. Si una subdependencia es vulnerable y no se actualiza, considera las anulaciones o contactar a los mantenedores. - Dependencias mínimas: No incluyas paquetes que no necesites. Cada dependencia adicional es otro posible agujero. Por ejemplo, si solo necesitas una pequeña función, podría ser más seguro implementarla que incluir una librería de 30 funciones en la que tendrás que confiar y monitorizar.
- Monitoriza los avisos: Mantente al tanto de los avisos de seguridad en el ecosistema Node/JS. Suscríbete a las listas de correo de seguridad de Node o a las alertas de Dependabot de GitHub para tus repositorios.
Aquí es donde el análisis de dependencias de Aikido y las correcciones impulsadas por IA realmente brillan. Aikido escanea continuamente tu árbol de dependencias contra una base de datos de vulnerabilidades. Si surge un nuevo CVE para, por ejemplo, Express o Lodash, recibirías una notificación e incluso una sugerencia de corrección automática (por ejemplo, «actualizar de Lodash 4.17.11 a 4.17.21 para parchear CVE-2020-8203»). Las herramientas amigables para desarrolladores significan que no es solo un informe: Aikido puede abrir una solicitud de extracción con la versión actualizada. Además, la capacidad SafeChain de Aikido (un firewall integrado en la aplicación para tu gestor de paquetes) puede evitar la instalación de paquetes maliciosos conocidos. Al integrar estas herramientas, tu equipo puede reducir drásticamente el período de exposición desde que se revela una vulnerabilidad de la librería hasta que la remedias en tu aplicación.
9. Paquetes NPM maliciosos y ataques a la cadena de suministro
No todos los ataques provienen de errores de codificación; algunos provienen del código que thought en la que podrías confiar. El ecosistema npm ha sufrido ataques a la cadena de suministro donde los atacantes subvierten el suministro de paquetes para insertar código malicioso. Esto puede ocurrir mediante técnicas como typosquatting (publicar un paquete con un nombre similar a uno popular, esperando que alguien lo escriba mal o lo instale por error), o comprometiendo a los mantenedores de proyectos legítimos. Un incidente infame fue el event-stream ataque en 2018: un atacante convenció al mantenedor de event-stream (un paquete ampliamente utilizado) para ceder el control, y luego lanzó una nueva versión que incluía una dependencia oculta (flatmap-stream) que contenía malware. Durante un par de meses, esa actualización maliciosa fue descargada millones de veces y se dirigió específicamente a una aplicación de monedero de Bitcoin (Copay) para robar claves de criptomonedas.
Otros ejemplos incluyen paquetes como ua-parser-js, node-ipc, y event-source-polyfill que fueron secuestrados por atacantes o saboteados por sus propios desarrolladores para entregar cargas útiles no deseadas (como spyware, mineros de criptomonedas o scripts destructivos). En 2021, investigadores de seguridad demostraron ataques de «confusión de dependencias», donde si una empresa utiliza un nombre de paquete interno y un atacante publica un paquete con el mismo nombre en npm, las herramientas de compilación podrían descargar la versión del atacante. Estos escenarios son particularmente peligrosos porque pueden otorgar a los atacantes ejecución remota de código durante su compilación o en producción, sin explotar ninguna vulnerabilidad tradicional.
Mitigación:
- Verificar la autenticidad del paquete: Utilice hashes de integridad de paquetes (npm utiliza automáticamente
package-lockcon hashes sha512 para los paquetes; mantenga ese lockfile versionado). Considere habilitar 2FA en las cuentas de npm y prefiera paquetes de fuentes confiables. - Blindar las Dependencias Internas: Si tiene paquetes privados, asegúrese de que su registro o proceso de compilación no los obtenga accidentalmente del registro público. Defina espacios de nombres para los paquetes internos o utilice registros con ámbito.
- Monitorear Scripts de Instalación: Tenga cuidado con los paquetes que tienen scripts de instalación/post-instalación. Audite lo que hacen esos scripts (algunos paquetes maliciosos los utilizan para ejecutar comandos dañinos durante la instalación).
- Utilice herramientas de seguridad: Aproveche la auditoría de npm y otras herramientas para identificar anomalías. Por ejemplo, si un paquete muy utilizado lanza de repente una nueva versión menor después de un largo período de inactividad, trátelo con cautela (como ocurrió con la versión 3.3.6 de event-stream).
- Principio de Mínimo Privilegio: Al ejecutar builds o CI, hágalo en entornos sandbox. Para producción, considere mecanismos como los de Node
--experimental-policypara controlar qué módulos puedenRequerirqué, o la contenerización para limitar los daños.
Aikido ayuda a proteger tu cadena de suministro de software. Aikido SafeChain, por ejemplo, puede analizar los metadatos del paquete e incluso el contenido del paquete en busca de indicadores maliciosos. Puede bloquear la instalación de paquetes que se sabe que están comprometidos o que exhiben un comportamiento sospechoso (como scripts post-instalación ofuscados). El feed de inteligencia de amenazas de Aikido rastrea el malware en paquetes de código abierto, por lo que si mañana una librería popular es secuestrada, Aikido puede advertirte o prevenir actualizaciones a la versión comprometida. Además, el SAST de Aikido puede detectar el uso de operaciones sensibles en las dependencias (como si una dependencia de repente comienza a ejecutar comandos de shell o a acceder a la red de una manera inesperada). Al integrar estas herramientas en tu pipeline, añades una sólida capa de defensa contra el próximo ataque de estilo event-stream, teniendo esencialmente un revisor de código automatizado para código de terceros.
10. Secretos Codificados y Credenciales Expuestas
La codificación de secretos (claves API, tokens, contraseñas) en su código JavaScript o configuración es una práctica arriesgada que, lamentablemente, sigue siendo común. En el código frontend, cualquier secreto (por ejemplo, una clave API para un servicio de terceros) es visible para el usuario final y debe tratarse como público; sin embargo, los desarrolladores a veces lo olvidan y dejan tokens sensibles en el paquete JS. En el código backend de Node.js o en los archivos de configuración, los secretos pueden ser enviados a git y terminar en el control de código fuente o en el paquete desplegado. La exposición de secretos puede conducir a accesos no autorizados, tomas de control de cuentas o facturas costosas (por ejemplo, si un atacante encuentra una clave API de un proveedor de la nube, puede desplegar recursos o volcar sus bases de datos).
La magnitud de este problema se destaca por la investigación: solo en 2024, se detectaron casi 23.8 millones de nuevos secretos codificados en commits públicos de GitHub, un aumento del 25% con respecto al año anterior. Se han producido filtraciones de alto perfil debido a credenciales expuestas; por ejemplo, una filtración de credenciales del New York Times y otra en Sisense se remontaron a la dispersión de secretos. Incluso en imágenes de Docker, se han encontrado miles de claves API incorporadas inadvertidamente. La conclusión: la exposición de secretos es rampante y a menudo la forma más fácil para que los atacantes accedan sin explotar un error de software.
Ejemplo real: En 2019, un desarrollador subió accidentalmente una cadena de conexión de MongoDB (con credenciales) a un repositorio público de GitHub. En cuestión de horas, los atacantes que escaneaban GitHub la encontraron, accedieron a la base de datos y retuvieron los datos para pedir un rescate. En otro caso, los desarrolladores de aplicaciones móviles dejaron una clave privada de Firebase en el JavaScript de la aplicación; los atacantes la extrajeron y accedieron a los datos de usuario en Firebase. Estos ejemplos demuestran que, ya sea en un .js archivo, un .env archivo enviado por error, o en cualquier parte de su base de código, los secretos son un objetivo fácil para los atacantes si se exponen.
Mitigación:
- Nunca codifique secretos: Utiliza variables de entorno o un servicio de gestión de secretos. Tu aplicación Node.js puede leer desde
process.enven tiempo de ejecución, en lugar de tener el secreto en el código fuente. Para las necesidades del frontend, considera proxyficar las solicitudes a través de tu backend para que el secreto no quede expuesto, o utiliza flujos OAuth que no requieran incrustar secretos. - Git Ignore y Escaneo: No hagas commit de
.envarchivos u otros archivos que contengan secretos. Utiliza.gitignorepara excluirlos. Además, utiliza herramientas de escaneo de secretos (GitHub tiene un escáner de secretos integrado para repositorios públicos, y las herramientas de terceros pueden escanear commits) para detectar cualquier secreto que se cuele. - Rotación de Claves: En caso de cualquier sospecha de que un secreto se haya filtrado, rótalo inmediatamente. Ten un plan para la rotación de claves y utiliza credenciales separadas para diferentes entornos (para que una fuga en desarrollo no comprometa producción, por ejemplo).
- Bóvedas y Gestión de Configuración: Utilice una bóveda de secretos adecuada o un gestor de secretos en la nube para almacenar y recuperar secretos en tiempo de ejecución, en lugar de guardarlos en archivos de configuración.
Aikido incluye capacidades de detección de secretos que escanean continuamente tu código y configuraciones en busca de patrones de credenciales. Por ejemplo, si alguien accidentalmente hace un commit de una clave de acceso de AWS o un token de API, Aikido lo señalaría (incluso durante una solicitud de extracción) con una alerta de alta prioridad. Reconoce patrones y también puede usar el contexto (por ejemplo, una cadena hexadecimal de 40 caracteres en un archivo de configuración podría ser señalada como una posible clave de API). Además, la plataforma de Aikido puede integrarse con el control de versiones para evitar que los secretos lleguen a producción, detectándolos en el pipeline de CI. Esto es similar a tener un guardián que verifica «¿Estás seguro de que quieres hacer commit de esa clave?». En caso de que se encuentre un secreto, Aikido puede ayudar a evaluar el impacto identificando dónde podría haberse propagado ese secreto e incluso sugiriendo una remediación (como qué claves rotar). Al emplear estas herramientas, los desarrolladores pueden hacer commits a los repositorios con la confianza de que no están publicando inadvertidamente las llaves del reino.
Conclusión
La fortaleza de JavaScript –su ubicuidad y flexibilidad desde el navegador hasta el backend– es precisamente lo que hace que asegurarlo sea una tarea tan crítica. Hemos visto lo fácilmente que un simple descuido (una salida no saneada, un paquete desactualizado, una clave API filtrada) puede desbaratar la seguridad de una aplicación. La buena noticia es que la concienciación y las mejores prácticas son de gran ayuda: al comprender estas principales vulnerabilidades, los desarrolladores pueden evitar errores comunes como evaluar datos no confiables o dejar una puerta abierta a través de ../ en una ruta. Adoptar una mentalidad de seguridad primero significa validar entradas, codificar salidas, actualizar dependencias y nunca asumir “nadie notará mi error”, porque si usted no lo detecta, un atacante lo hará eventualmente.
Integra la seguridad en tu flujo de trabajo de desarrollo. Adopta hábitos de codificación segura (revisa las hojas de trucos de OWASP, usa linters y verificadores de tipos para detectar problemas a tiempo). Y aprovecha las herramientas de seguridad integradas que trabajan contigo, desde el análisis estático de código hasta la auditoría de dependencias y el escaneo de secretos. Soluciones como Aikido te permiten integrar estas prácticas en tu pipeline de CI/CD, para que cada commit y build sea verificado automáticamente en busca de vulnerabilidades. Al detectar los problemas de forma temprana y frecuente, reduces el riesgo sin ralentizar el proceso. El mundo de JavaScript avanza rápido, pero con las salvaguardas adecuadas, puedes innovar igual de rápido sin dejar tu aplicación expuesta. Despliega con confianza y seguridad: ¡tus usuarios y tu equipo DevSecOps te lo agradecerán!
Sigue leyendo:
Las 9 principales vulnerabilidades de seguridad de contenedores Docker
Las 7 principales vulnerabilidades de seguridad en la nube
Las 10 principales vulnerabilidades de seguridad de aplicaciones web que todo equipo debería conocer
Las 9 principales vulnerabilidades y configuraciones erróneas de seguridad Kubernetes
Las principales vulnerabilidades de seguridad de código encontradas en aplicaciones modernas
Las 10 principales vulnerabilidades de seguridad de Python que los desarrolladores deberían evitar Las 9 principales vulnerabilidades de seguridad de la cadena de suministro de software explicadas

