Cada «npm install» es un acto de confianza. El mismo ecosistema de paquetes que agiliza el desarrollo en JavaScript es también uno de los principales vectores de ataques a la cadena de suministro. Cuando ejecutas un comando de instalación, estás incorporando un extenso árbol de dependencias, muchas de las cuales son desconocidas y están ocultas.
npm install es seguro la mayoría de las veces. Ese «la mayoría» implica mucho trabajo. La instalación no es simplemente una descarga, sino una ejecución, y los scripts del ciclo de vida de las dependencias se ejecutan con los permisos que ya tenga el entorno de instalación. En el portátil de un desarrollador o en un servidor de integración continua (CI), eso suele ser más que suficiente. El código se descarga, se descomprime y se ejecuta antes de que nadie lo haya revisado. Todo lo que se expone a continuación se refiere a npm v12, pnpm 11 y Yarn 4.10 a fecha de agosto de 2026, ya que los valores predeterminados en este ámbito han evolucionado rápidamente.
La trampa del «typosquatting»
Este ataque se produce cuando un atacante publica un paquete que contiene un error tipográfico. El error puede ser un simple error ortográfico en el nombre del paquete o una estrategia de formato totalmente diferente. Su aspecto es prácticamente idéntico al de los paquetes más populares y reproduce la misma funcionalidad.
- Manipulación de caracteres: Intercambio lodash por lodahs, o el uso de homógrafos (por ejemplo, sustituir la «l» por la «I»).
- Variaciones de formato: Uso de trucos con guiones (cross-env frente a crossenv) o la pluralización (color frente a colores).
- Confusión entre espacios de nombres y ámbitos: Creación de paquetes maliciosos con ámbito limitado que imitan a las bibliotecas oficiales.
Estos paquetes pueden ejecutar código arbitrario durante el proceso de instalación y sustraen todo tipo de credenciales, desde claves API y variables de entorno hasta credenciales de AWS, etc. Esto puede ocurrir con extrema rapidez, antes de que un desarrollador tenga tiempo de revisar el código.
Cómo funcionan los ataques de confusión de dependencias
Este ataque se aprovecha de las organizaciones que utilizan una configuración híbrida, es decir, un registro interno junto con el registro público de npm.
Los ataques de «confusión de dependencias» se producen cuando una empresa tiene un paquete interno y un atacante publica uno con el mismo nombre en el registro público. Por lo general, lo publican con un número de versión superior al del paquete interno. Si tu entorno de compilación puede resolver ese nombre en ambos registros, es posible que descargue el paquete público del atacante en su lugar. En ese paquete se encuentra el código malicioso.
Que esto ocurra depende de la configuración de tu registro, ámbito, proxy y archivo de bloqueo. Las configuraciones que se ven afectadas son aquellas que nadie ha auditado.
La forma de mitigar este riesgo es utilizar paquetes con ámbito y hacer que el enrutamiento sea determinista. Asigna explícitamente cada ámbito privado a tu registro privado en .npmrc, y asegúrate de que nada en tu cadena de proxy recurra silenciosamente al ámbito público. Reclama el ámbito correspondiente en npmjs.com añade una segunda capa de seguridad, ya que un atacante no puede publicar bajo un ámbito que ya te pertenece. Si has instalado algo en los últimos años, ya sabes lo que es un paquete con ámbito. Un paquete con ámbito tiene un aspecto similar a este: @my-org/cool-package. El primer carácter es el símbolo @, seguido de tu nombre o el de tu organización y el paquete que estás instalando.
Sin esas medidas de seguridad, el uso de ámbitos por sí solo no detendrá por completo el ataque. Un ámbito, en sí mismo, es una convención de nomenclatura, no un control. Asegurarse de que tu plataforma de CI/CD esté configurada correctamente también ayuda a mitigar el riesgo.
¿Qué ocurre cuando se vulnera la seguridad de la cuenta de un responsable de mantenimiento?
Tanto el «typosquatting» como la confusión de dependencias implican que instales algo que no tenías intención de instalar. La versión más sofisticada se salta ese paso. El atacante se hace con el control de un paquete en el que ya confías, que ya has revisado y al que ya has asignado un «pin».
Este es el vector que más daño está causando en estos momentos. Una campaña de phishing dirigida contra los responsables de mantenimiento de npm en septiembre de 2025 dio lugar al gusano Shai-Hulud, que robó tokens de la nube y los utilizó para propagarse a otras cuentas. El 4 de agosto de 2026, un atacante accedió a la cuenta de GitHub del responsable de mantenimiento de keyv, una biblioteca con más de 100 millones de descargas semanales, y publicó versiones diseñadas para robar credenciales en keyv, cacheable, flat-cache, caché-de-entradas-de-archivoy otros de ese grupo. Los rastreadores contabilizaron cientos de nombres de paquetes afectados y más de mil versiones afectadas en tan solo un día.
Esta es la parte que debería preocuparte. El lanzamiento se realizó a través del propio flujo de trabajo de GitHub Actions del responsable del mantenimiento, por lo que incluía una procedencia válida respaldada por OIDC y un hash de integridad válido. Ambos describían exactamente el artefacto malicioso que había generado el flujo de trabajo legítimo. La procedencia establece dónde y cómo se compiló un paquete. No dice nada sobre quién tenía las claves.
Esto se detectó gracias a las herramientas de análisis de comportamiento y a los controles de edad de las versiones, no mediante comprobaciones criptográficas. Es importante contar con la trazabilidad, pero no es el objetivo final.
Por qué no se auditan las dependencias transitivas
Una dependencia directa, aunque haya sido auditada, puede acarrear numerosas dependencias transitivas que no hayas visto y de las que no seas consciente. Estas dependencias ocultas pueden encontrarse a una profundidad de entre 5 y 10 o más niveles dentro del árbol de dependencias.
La mayoría de las dependencias se encuentran en lo más profundo del árbol del proyecto, donde rara vez se revisan manualmente, lo que crea una «caverna oscura» totalmente expuesta a los atacantes. Esta falta de visibilidad es un vector principal para los ataques a la cadena de suministro. Estos se producen cuando actores malintencionados se infiltran en los paquetes o los sustituyen por completo, pasando a menudo desapercibidos durante la instalación, un riesgo que ni siquiera algunas herramientas de generación de código basadas en IA logran abordar, tal y como se señala en mi entrada del blog sobre Dockerfile.
Mientras que npm ls es una herramienta útil para visualizar árboles de dependencias completos, no detecta vulnerabilidades ni comportamientos sospechosos. Por eso las herramientas de análisis de la composición del software (SCA) son importantes para detectar problemas ocultos en lo más profundo de la pila.
| Herramienta | Se le da bien | Lo echaré de menos |
| Dependabot | CVE conocidos en tu árbol, solicitudes de incorporación de cambios (PR) automatizadas para actualizar los números de versión | Paquetes maliciosos totalmente nuevos, ya que aún no existe ningún CVE |
| Toma de corriente | Señales de comportamiento, nuevos scripts de instalación, acceso inesperado a la red o al sistema de archivos | No se creó inicialmente como una base de datos de CVE |
| Snyk | Cobertura de CVE, además de comprobaciones de la cadena de suministro y de las licencias | Hay que ajustarlo antes de que la señal de salida deje de ser ruido. |
Dependabot es la opción básica más sencilla si tus repositorios están en GitHub. Eso sí, no lo confundas con la detección de paquetes maliciosos, ya que un paquete publicado hace una hora aún no tiene ningún CVE con el que compararlo.
¿Cómo se preinstalación y los scripts de postinstalación ejecutan código
preinstalar y postinstall en package.json ejecutan código automáticamente una vez que se ha descargado y descomprimido un paquete, antes de que el desarrollador haya revisado su contenido.
Estos scripts se dirigen a activos de gran valor, como sistemas bancarios, servidores de compilación, etc. Lo mejor de lo mejor, por así decirlo. Extraen credenciales vitales, como archivos .env , tokens de AWS y claves SSH, de las que se nos recuerda constantemente NO de incluir en el control de versiones.
Algunos scripts realizan comprobaciones del entorno para detectar entornos aislados o sistemas sometidos a una estrecha vigilancia antes de ejecutar su carga útil, centrándose primero en los entornos menos protegidos.
Este sigue siendo el método de distribución preferido. Todas las versiones infectadas de la campaña de agosto de 2026 incluían una un dropper .
Sin embargo, al final se han producido cambios en la configuración predeterminada. pnpm dejó de ejecutar scripts del ciclo de vida de las dependencias de forma predeterminada en la versión 10, y npm v12, lanzada el 8 de julio de 2026, adoptó la misma postura, gestionada a través de npm approve-scripts. Un script no aprobado se omite con una advertencia, así que configura strict-allow-scripts si prefieres que la integración continua (CI) falle. En npm 11 o versiones anteriores, el indicador se encarga de ello por ti:
bash npm install --ignore-scripts
Conviene saber que nada de esto afecta a la ejecución en el momento de la importación. Un paquete comprometido cuyo código de nivel superior se ejecute cuando tu aplicación llame a require() elude por completo los controles del script de instalación.
Por qué la antigüedad del paquete es un indicador de seguridad
La mayoría de estos ataques se detectan, normalmente en cuestión de horas y no de semanas. El problema es que tu CI ya ha descargado la versión defectuosa durante esas horas.
Una edad mínima de lanzamiento reduce ese margen sin que nadie tenga que auditar nada. Todos los gestores de paquetes principales lo incluyen ya. pnpm 11 pasa a minimumReleaseAge activado por defecto en 1.440 minutos, mientras que Yarn 4.10 establece por defecto npmMinimalAgeGate en tres días, y npm tiene min-release-age a partir de la versión 11.10, pero lo deja desactivado, por lo que debes configurarlo tú mismo. Presta atención a las unidades, ya que npm cuenta los días y pnpm cuenta los minutos.
# .npmrc min-release-age=7
La mayoría de los profesionales se decantan por un plazo de entre tres y siete días. Esto no resuelve el problema de un paquete que ya era malicioso desde el primer día, ni el de uno que permanece inactivo más allá del umbral establecido.
npx requiere la misma consideración. Cuando se descarga algo nuevo, tu archivo de bloqueo no determina qué versión se elige, así que fija la versión que invocas con npx [email protected].
Cómo instalar paquetes de npm de forma segura
- Asegúrate de guardar los archivos de bloqueo y utiliza npm ci para obtener compilaciones deterministas y fiables en entornos de CI. El archivo de bloqueo junto con npm ci es lo que realmente fija tu árbol resuelto, incluidas las dependencias transitivas.
- Especifica las versiones exactas en package.json eliminando los símbolos de prefijo (^, ~) en aquellos casos en los que quieras controlar el momento de la actualización de las dependencias directas. Esto aporta previsibilidad más que seguridad, ya que no tiene ningún efecto sobre el árbol transitivo.
- Que el gestor de paquetes bloquee los scripts de dependencias de forma predeterminada. Ese es ya el comportamiento en pnpm 10 y versiones posteriores, así como en npm v12, y se trata de –ignore-scripts en versiones anteriores.
- Revisa tus paquetes con regularidad y utiliza herramientas de SCA como Dependabot, Socket o Snyk para detectar anomalías en tu árbol de dependencias.
- Activa una edad mínima de liberación de entre tres y siete días.
- Activa la autenticación multifactorial (MFA) en todas las cuentas con permisos de publicación y procura que los tokens de publicación sean específicos y de corta duración.
Bloquear scripts tiene un coste real, así que tómalo con calma. Los módulos nativos y las herramientas de automatización del navegador requieren sus propios pasos de instalación, y un enfoque, bcrypt, Prisma, Playwright y Cypress suelen ser las víctimas habituales. En la integración continua (CI), bloquea por defecto, aprueba solo lo que necesites y ejecuta esas compilaciones en un entorno que no contenga tus credenciales de producción. En un portátil, aprueba el paquete concreto que falla en lugar de desactivar la protección para todo. Estate atento a los fallos silenciosos en cualquier caso, ya que una compilación nativa bloqueada puede completarse sin errores y solo manifestarse más tarde como un módulo que falta en tiempo de ejecución.
Reflexiones finales sobre la seguridad de la cadena de suministro de npm
La seguridad de la cadena de suministro de software nunca es un requisito operativo que se cumpla una sola vez. La seguridad es una práctica continua y siempre debe ser una prioridad. Hay tres aspectos que suelen dejarse de lado hasta que se desata el caos: el rendimiento, la accesibilidad y —como habrás adivinado— la seguridad. Estar al día de las herramientas y los trucos que te ayudan a mantener la seguridad forma parte del trabajo de un desarrollador. Ten en cuenta las medidas de defensa prácticas y mantén siempre la seguridad como prioridad a la hora de lanzar un producto.

