Blog técnico

Volver al blog

Dependencias de JavaScript: qué riesgos introduces al instalarlas

Instalar una dependencia añade código, mantenedores y decisiones de instalación al proyecto. Por qué uso pnpm y qué límites sigo revisando.

Publicado
Lectura
10 minutos
Temas
Seguridad · JavaScript · pnpm

El riesgo de una dependencia no empieza cuando la importas en un componente. Empieza antes, al decidir que vas a ejecutar pnpm add o npm install en tu máquina y en la de tu equipo.

Una librería puede ahorrar horas. También puede incorporar cientos de paquetes transitivos, un script que se ejecuta al instalar o una versión publicada hace veinte minutos. No es una razón para dejar de usar dependencias. Es una razón para dejar de tratarlas como una línea de configuración sin consecuencias.

Este tema ha cobrado más peso durante 2026 por varios compromisos de paquetes publicados en npm. No hay una única vulnerabilidad del CLI de npm que haga que pnpm sea automáticamente seguro. El problema más persistente es de cadena de suministro. Un paquete legítimo puede publicar una versión comprometida, y el gestor de paquetes es el momento en que ese código entra en tu entorno.

Por eso uso pnpm en este portfolio. No porque me proteja de todo, sino porque me permite poner algunas barreras por defecto que me parecen razonables para un proyecto personal que sigue creciendo.

Una dependencia no es solo el paquete que buscas

Cuando instalas una dependencia directa, también aceptas su árbol de dependencias, las personas o la organización que publican sus versiones y la forma en que el gestor las resuelve. A veces el coste real no está en el tamaño del paquete, sino en lo que pasa durante la instalación o al actualizarlo meses después.

Hay varios riesgos distintos mezclados bajo la palabra “dependencia”.

  • Un paquete puede estar abandonado y dejar de recibir correcciones.
  • Un nombre parecido al de una librería conocida puede llevar a un paquete distinto.
  • Una actualización puede incluir cambios que no esperabas.
  • Un paquete transitorio puede añadir scripts de instalación, una URL remota o una dependencia desde Git.
  • Un mantenedor o una cuenta de publicación pueden verse comprometidos.

Un lockfile ayuda a que el equipo instale las mismas versiones. No decide que esas versiones sean buenas. Congela una decisión que ya tomaste. Esa diferencia importa cuando aparece una alerta o cuando alguien propone actualizar todo sin revisar el diff.

El cambio reciente en npm es una mejora, no el final del problema

Desde npm 12, publicado en julio de 2026, los scripts de ciclo de vida de dependencias no se ejecutan por defecto. Las dependencias desde Git y las URLs remotas también requieren permiso explícito. Es un cambio importante porque los scripts preinstall, install y postinstall han sido una vía habitual para ejecutar código durante una instalación.

Es buena noticia. También evita una conclusión cómoda. Aprobar un script no convierte al paquete en fiable, y desactivar scripts no sustituye revisar lo que se instala. El gestor reduce una clase de exposición. El criterio sobre la dependencia sigue siendo tuyo.

La comparación con pnpm debería hacerse desde ahí. No desde “npm es inseguro”. npm ha endurecido sus valores por defecto. pnpm lleva desde la versión 10 sin ejecutar automáticamente los postinstall de dependencias y añade algunas políticas que, ahora mismo, me resultan útiles para retrasar y acotar lo que llega al proyecto.

Por qué pnpm me encaja mejor ahora

El motivo principal no es que instale rápido ni que ocupe menos espacio. Es que permite convertir varias decisiones de seguridad en configuración versionada junto al proyecto.

Los builds no se ejecutan por inercia

En este repositorio hay un pnpm-workspace.yaml con una lista explícita de dependencias a las que permito construir durante la instalación.

allowBuilds:
  '@parcel/watcher': true
  esbuild: true
  sharp: true

Eso no significa que esas tres dependencias sean infalibles. Significa que no quiero que una dependencia nueva ejecute un build solo porque alguien la ha añadido al árbol. Si entra otra con postinstall, pnpm pide que la decisión sea explícita.

Es una diferencia útil cuando el problema no es solo un paquete malicioso creado ayer. También importa una versión comprometida de una dependencia que antes no necesitaba ejecutar nada al instalarse.

Una versión recién publicada puede esperar

pnpm 11 tiene una edad mínima de publicación de un día por defecto. Cuando instalas o actualizas, evita resolver versiones que acaban de salir. Esa espera no detecta malware. Compra tiempo para que un paquete comprometido sea descubierto, retirado o señalado antes de entrar en un proyecto.

En este portfolio hay excepciones para paquetes concretos de Astro que ya estaban decididos en la actualización actual. No las veo como una lista para copiar. Cada excepción reduce la protección y debería tener una razón clara, sobre todo si es una dependencia nueva o poco conocida.

Para una aplicación que no necesita la última versión el mismo día, retrasar actualizaciones me parece una medida más sensata que instalar todo lo nuevo por reflejo. Para un parche de seguridad importante, el criterio cambia. Ahí hay que revisar el aviso, la versión afectada y el coste de esperar.

También puede cerrar fuentes menos habituales

Pnpm permite bloquear dependencias transitivas que vengan de Git o de una URL de tarball con blockExoticSubdeps. Tiene además políticas de confianza y puede fijar paquetes a un registro concreto en el lockfile cuando se trabaja con varios registros.

No activaría una opción solo por acumular seguridad. Primero comprobaría si rompe una dependencia legítima y documentaría por qué existe esa excepción. Lo que me interesa es que estas decisiones estén visibles en el repositorio y no escondidas en la configuración local de una persona.

Pnpm no está fuera del alcance de las vulnerabilidades

Usar pnpm no te permite dejar de actualizar pnpm.

En mayo de 2026 se publicó una vulnerabilidad de path traversal en pnpm que podía reemplazar rutas del proyecto mediante una dependencia transitiva, incluso con --ignore-scripts. Afectaba a versiones anteriores a 10.34.0 y a la rama 11 anterior a 11.4.0. Este proyecto fija pnpm@11.19.0, fuera de esos rangos, pero el aprendizaje no es “pnpm ganó”. El propio gestor de paquetes también forma parte de la cadena de suministro.

Por eso no trataría --ignore-scripts como un modo seguro absoluto. Es una capa útil. No garantiza que un bug del gestor, una configuración de registro débil o una dependencia maliciosa no puedan causar otro problema.

Las versiones y las medidas de los gestores cambian. Si vuelves a este artículo dentro de unos meses, mira los avisos oficiales antes de copiar una configuración. A fecha de agosto de 2026, npm 12 ha endurecido las instalaciones y pnpm ofrece además edad mínima de publicación, control explícito de builds y políticas de procedencia. Esa es la comparación práctica, no una guerra de herramientas.

Lo que miro antes de añadir algo

No tengo una fórmula que convierta un paquete en seguro. Sí intento frenar el gesto automático de buscar una función, encontrar el primer resultado y añadirla.

Primero me pregunto si de verdad hace falta. Una utilidad que cabe en unas pocas líneas y pertenece al dominio del proyecto puede ser más fácil de revisar y mantener que una librería entera. En cambio, para cosas complejas como un parser, un motor de fechas o una integración con un protocolo, escribir una solución propia por orgullo suele aumentar el riesgo.

Después miro cosas más concretas.

  • Qué problema resuelve y si el proyecto ya tiene una forma de resolverlo.
  • Quién lo mantiene, cuándo publicó una versión estable y cómo documenta cambios.
  • Cuántas dependencias añade y si necesita scripts de instalación.
  • Qué versión exacta acaba en pnpm-lock.yaml.
  • Qué cambia al actualizar, en lugar de aceptar una actualización masiva sin leerla.

Si el paquete es nuevo para mí o su comportamiento durante instalación me preocupa, prefiero revisar el tarball o sus archivos publicados antes de introducirlo en el proyecto. No necesito auditar cada línea de cada dependencia para trabajar con JavaScript. Necesito reconocer cuándo una decisión pequeña está ampliando demasiado la superficie de confianza.

El lockfile y el entorno de instalación cuentan

Cometer pnpm-lock.yaml es imprescindible para repetir instalaciones, pero también hay que usarlo bien. En CI, una instalación congelada evita que un rango como ^7.0.0 se convierta de repente en una versión nueva durante un despliegue.

Eso no evita que una versión ya fijada tenga una vulnerabilidad conocida. Para eso hacen falta avisos, revisiones periódicas y actualizaciones con intención. Tampoco protege secretos que estén disponibles para un script de instalación. En una máquina o CI con tokens de publicación, credenciales cloud y claves SSH, instalar dependencias merece más cuidado que en un entorno aislado.

Si alguna vez publicara paquetes desde automatización, preferiría la publicación de confianza de npm con OIDC antes que un token de escritura permanente. No porque elimine todos los riesgos, sino porque evita dejar una credencial reutilizable en los secretos de CI.

La decisión que quiero poder explicar

No quiero que mi respuesta a una alerta sea cambiar de gestor de paquetes y dar el problema por resuelto. Quiero poder explicar por qué esa dependencia está en el proyecto, qué versión se instaló, qué se autorizó durante la instalación y qué haría si apareciera un aviso mañana.

Para este portfolio, pnpm encaja mejor ahora porque hace visibles tres decisiones que valoro. Qué paquetes pueden construir, cuánto tiempo espero antes de resolver una versión nueva y qué versiones exactas van a instalarse. Eso no sustituye mantenimiento, revisión ni actualizaciones. Hace que sea más difícil olvidarse de ellas.

Esta es una continuación natural de seguridad web explicada para desarrolladores y de la revisión antes de publicar una web. La seguridad de una web no empieza al desplegarla. Empieza bastante antes, cuando eliges qué código ajeno va a entrar en el repositorio.