⏱️ Lectura: 16 min

El 28 de abril de 2026 la fundación detrás de pnpm publicó la versión 11.0 del gestor de paquetes JavaScript que en los últimos cuatro años pasó de proyecto alternativo a opción default para una porción creciente de equipos serios. El anuncio oficial en pnpm.io/blog/releases/11.0, el release en GitHub firmado por Zoltan Kochan —mantenedor principal— y la cobertura analítica de InfoQ coinciden en que esta no es una versión menor: pnpm 11 cambia la postura de seguridad por defecto del gestor, reemplaza la arquitectura interna de la store por una base de datos SQLite, drop-ea soporte de Node.js 18-21, distribuye en ESM puro, y agrega siete comandos nuevos —entre ellos pnpm sbom para generar Software Bill of Materials en formatos CycloneDX y SPDX—.

📑 En este artículo
  1. La nueva línea base: minimumReleaseAge + blockExoticSubdeps
    1. minimumReleaseAge: bloquear las primeras 24 horas
    2. blockExoticSubdeps: cerrar la puerta de las dependencias raras
    3. strictDepBuilds y verifyDepsBeforeRun
  2. Mini Shai-Hulud y por qué la velocidad importa
  3. El otro lado: la store reescrita en SQLite
  4. Lo que rompe: migración desde pnpm 10
    1. Versión de Node.js
    2. Configuración: .npmrc ya no es para pnpm
    3. allowBuilds reemplaza cinco settings legacy
    4. Audit migrado a GHSA
    5. Distribución pure ESM
  5. Comandos nuevos que vale la pena conocer
  6. La pregunta operativa: ¿npm y Yarn van a seguir el camino?
  7. Cómo actualizar
  8. Lección de fondo
  9. Fuentes
    1. 📚 Artículos relacionados

La pieza más relevante para cualquier equipo que despliegue código JavaScript en producción es el cambio en los defaults de mitigación contra ataques a la cadena de suministro. Específicamente, minimumReleaseAge ahora vale 1.440 minutos —24 horas— por defecto, lo cual significa que pnpm 11 rehúsa instalar versiones de paquetes que se hayan publicado en las últimas 24 horas salvo que el operador relaje explícitamente la regla. La medida ataca directamente la ventana temporal en que se ejecutan los compromisos modernos del registro npm: un atacante consigue credenciales de un publisher, sube una versión maliciosa, y depende de instalaciones automáticas en CIs que se disparan en minutos. Bloquear las primeras 24 horas le da a la comunidad —investigadores como Socket, npm registry team, los propios mantenedores de paquetes— el tiempo de detectar y purgar la versión maliciosa antes de que entre a tu pipeline.

Este artículo es continuación natural de cobertura previa en este blog sobre la campaña Contagious Interview que infectó 1.700 paquetes en abril, sobre la doble ola TeamPCP/Trivy + ShinyHunters/Hashicorp del 1 de mayo, sobre el CVE-2026-3854 de GitHub que daba RCE con un git push del 30 de abril, y la onda larga del ataque a Rspack que en enero de 2025 había forzado a pnpm 10 a bloquear scripts de lifecycle por defecto. La política de defaults seguros que pnpm consolida hoy no es un capricho de ingeniería: es la respuesta acumulada del proyecto a más de un año de ataques exitosos al ecosistema. Vale la pena entenderla por dentro.

La nueva línea base: minimumReleaseAge + blockExoticSubdeps

minimumReleaseAge: bloquear las primeras 24 horas

La idea es elegantemente simple. La documentación oficial de mitigación lo explica así: cuando pnpm resuelve dependencias, descarta cualquier versión cuyo published_at sea más reciente que el umbral configurado. El valor por defecto en pnpm 11 es 1440 minutos = 1 día.

# pnpm-workspace.yaml
minimumReleaseAge: 1440          # default en pnpm 11
# minimumReleaseAge: 10080       # una semana, para infraestructura crítica
# minimumReleaseAge: 0           # opt-out global (no recomendado)

Para casos puntuales —parche de seguridad emitido por mantenedores de un paquete crítico, hotfix urgente del propio equipo— existe un escape hatch:

minimumReleaseAge: 1440
minimumReleaseAgeExclude:
  - "@my-org/*"                  # paquetes propios sin gating
  - "react"                      # un paquete específico que necesitás al instante

El razonamiento detrás del valor de 24 horas está documentado por el equipo: la mayoría de los paquetes maliciosos publicados en npm son detectados y removidos del registro en menos de un día. La ventana de exposición típica para un usuario que instala automáticamente —en CI, con npm install o pnpm install desde un container que se construye en cada push— es de minutos, no horas. Comprimir 24 horas de aire entre publicación y resolución reduce esa ventana a casi cero para la mayoría de incidentes históricos analizados.

blockExoticSubdeps: cerrar la puerta de las dependencias raras

El segundo default nuevo es blockExoticSubdeps: true. Una dependencia exótica es cualquiera que se resuelve fuera del registro estándar: un tarball remoto, un repositorio Git, un protocolo link: o file: apuntando a directorios fuera del workspace. Estas formas de declarar dependencias son legítimas en algunos workflows —monorepos con packages cruzados, forks privados— pero también son un vector clásico de ataque: los registries no las indexan ni escanean, los advisories no las cubren, y un atacante con commit access a un repositorio aparentemente inocente puede inyectar código sin que ningún sistema lo detecte.

El nuevo default rechaza esas resoluciones para subdependencias —dependencias indirectas, traídas por paquetes que vos no controlás—. Las dependencias directas de tu propio package.json siguen pudiendo declararse así, pero pnpm cortarse el camino para que un paquete de tu node_modules traiga, transitivamente, código desde un Git arbitrario.

strictDepBuilds y verifyDepsBeforeRun

Hay dos defaults adicionales que vale la pena nombrar:

  • strictDepBuilds: true — pnpm falla la instalación si una dependencia declara un build script y no está explícitamente permitida en allowBuilds. La opción amigable de pnpm 10, donde el script simplemente no se ejecutaba, deja el estado limpio pero no avisaba: ahora avisa.
  • verifyDepsBeforeRun: true — antes de ejecutar cualquier script (pnpm run, pnpm exec), pnpm verifica que node_modules esté en sincronía con pnpm-lock.yaml. Esto previene que un build corra contra una resolución antigua después de que cambiaste el lockfile pero olvidaste reinstalar.

Mini Shai-Hulud y por qué la velocidad importa

Para entender por qué pnpm endurece estos defaults conviene mirar un caso concreto reciente. El equipo de Socket ancla su análisis de pnpm 11 en una campaña que apodaron Mini Shai-Hulud: un atacante comprometió cuentas de mantenedores en npm, PyPI y Packagist simultáneamente, y publicó versiones envenenadas de paquetes con un script preinstall que descargaba un runtime de Bun ofuscado, lo ejecutaba, y exfiltraba credenciales locales —tokens de GitHub, claves SSH, archivos de ~/.aws/credentials—. El patrón es reconocible: lo vimos en Rspack, lo vimos en la campaña Contagious Interview con 1.700 paquetes infectados, lo vimos en el incidente Mini Shai-Hulud, y lo veremos otra vez.

Lo que hace particularmente efectivos a estos ataques es la combinación de tres factores:

  • Velocidad. La cadena de eventos —compromiso → publicación → instalación automática en CIs de víctimas— ocurre en minutos.
  • Escala. Un solo paquete popular puede tener millones de descargas semanales y aparecer como dependencia transitiva de paquetes que sí controlás.
  • Confianza implícita. Tu CI confía en npm.org, npm.org confía en el publisher, el publisher fue comprometido. La cadena de confianza no detecta la pérdida.

Las dos defensas que pnpm 11 activa por defecto —minimumReleaseAge y blockExoticSubdeps— atacan directamente el primer y tercer factor. Bloquear 24 horas inserta latencia donde antes había ninguna. Bloquear subdependencias exóticas elimina vías de cargar código sin pasar por el registry. Socket es honesto en su análisis: pnpm 11 «no habría prevenido cada parte de esta campaña» —los ataques modernos combinan múltiples técnicas—, pero las dos defensas suman un eslabón importante que antes no existía por defecto en ningún gestor mainstream de JavaScript.

El otro lado: la store reescrita en SQLite

La parte menos discutida pero técnicamente más interesante de pnpm 11 es la nueva versión del content-addressable store, llamada internamente Store v11. La store es el directorio donde pnpm guarda todos los paquetes que descargó alguna vez, deduplicados por hash, para que múltiples proyectos puedan reutilizarlos sin duplicación de disco.

Hasta pnpm 10, la store mantenía un índice como millones de archivos JSON —uno por paquete— bajo $STORE/index/. Para un usuario activo que tiene varios proyectos sobre Node.js, ese directorio puede acumular cientos de miles de archivos pequeños y la performance del sistema de archivos se vuelve un cuello de botella: cada operación de listado, cada readdir, cada lookup es un syscall.

Pnpm 11 reemplaza ese diseño con una única base de datos SQLite ubicada en $STORE/index.db. Las propiedades técnicas son notables:

  • Valores en MessagePack, un formato binario compacto y rápido de deserializar.
  • WAL mode (Write-Ahead Logging) para permitir lecturas concurrentes sin bloquear escrituras.
  • Manifests bundled en el índice: name, version, bin, engines, scripts se guardan directamente en la base, eliminando la necesidad de leer package.json desde la CAS durante la resolución.
  • Hex digests en lugar de strings de integridad completos del estilo <algo>-<digest>, con el algoritmo de hash registrado una sola vez por archivo en lugar de por entrada. Esto evita conversiones base64→hex en cada lookup de path en la CAS.

A nivel de instalación en frío, los desarrolladores reportan reducciones significativas. El cambio elimina aproximadamente 30.000 syscalls de rename por instalación en frío gracias a escritura directa al CAS, usa el cliente HTTP undici —el mismo que usa Node.js internamente— y pre-aloca memoria para descargas de tamaño conocido. La instalación de un runtime de Node.js además ya no extrae los binarios de npm, npx y corepack por defecto, cortando aproximadamente la mitad de los archivos que pnpm tenía que hashear, escribir a la CAS y enlazar.

Lo que rompe: migración desde pnpm 10

pnpm 11 no es un upgrade transparente. Estos son los breaking changes que un equipo necesita planificar antes de actualizar.

Versión de Node.js

# Verificar tu versión actual
node --version

# pnpm 11 requiere Node 22 o superior
# Si estás en 18, 19, 20 o 21, primero actualizá Node
nvm install 22
nvm use 22

Para distribuciones que aún empaquetan Node 20 o 18 LTS, esto puede requerir cambiar a un repositorio externo (NodeSource, devsnek/node) o usar un volume manager como fnm, nvm o el propio pnpm runtime set —que ahora también gestiona instalaciones de Node—.

Configuración: .npmrc ya no es para pnpm

Hasta pnpm 10, configuraciones específicas de pnpm como auto-install-peers o prefer-frozen-lockfile se podían declarar en .npmrc. En pnpm 11, .npmrc queda restringido a auth y registry settings. Cualquier configuración propia de pnpm debe vivir en uno de:

# pnpm-workspace.yaml (configuración por workspace)
packages:
  - "packages/*"
auto-install-peers: true
prefer-frozen-lockfile: true
minimumReleaseAge: 1440
# ~/.config/pnpm/config.yaml (configuración global)
storeDir: /var/cache/pnpm
verifyStoreIntegrity: true

Las variables de entorno también cambian de prefijo: npm_config_* ya no funciona; ahora es pnpm_config_*. Esto rompe scripts de CI que pasaban configuración inline con npm_config_registry=https://....

allowBuilds reemplaza cinco settings legacy

Cinco campos distintos que controlaban qué scripts de lifecycle se permitían se unificaron en un solo allowBuilds:

# Antes (pnpm 10)
onlyBuiltDependencies: ["esbuild", "sharp"]
neverBuiltDependencies: ["puppeteer"]
ignoredBuiltDependencies: ["@playwright/test"]
ignoreDepScripts: false
onlyBuiltDependenciesFile: "./trusted.json"

# Ahora (pnpm 11)
allowBuilds:
  - esbuild
  - sharp
  - "!puppeteer"          # explícitamente bloqueado
  - "!@playwright/test"

La consolidación es lógica pero exige rescribir la configuración existente.

Audit migrado a GHSA

auditConfig.ignoreCves se renombró a auditConfig.ignoreGhsas. La razón: GitHub Security Advisories (GHSA) tienen identificadores más estables y mejor cobertura para el ecosistema npm que los CVEs tradicionales. La migración es directa, pero hay que pasar por todos los lockfiles del workspace.

Distribución pure ESM

pnpm 11 ya no embarca un build CommonJS. Si en algún script tenés algo como:

const pnpm = require("pnpm");

falla en pnpm 11. Hay que migrar a import o usar un dynamic import:

const pnpm = await import("pnpm");

Para uso normal en línea de comandos, esto no afecta —solo afecta integraciones programáticas—.

Comandos nuevos que vale la pena conocer

pnpm 11 agrega una colección de comandos que reflejan dónde el proyecto piensa que está la frontera de utilidad:

  • pnpm ci (alias clean-install, ic, install-clean) — equivalente al npm ci clásico. Borra node_modules, instala desde el lockfile congelado, falla si el lockfile no está en sincronía. Usable en CI sin sorpresas.
  • pnpm clean — borra node_modules en todo el workspace. Con --lockfile también borra los lockfiles si querés un reset total.
  • pnpm sbom — genera un Software Bill of Materials en formato CycloneDX 1.7 o SPDX 2.3. Esto pasó de ser un nice-to-have a un requerimiento regulatorio en muchos sectores —compliance gubernamental, supply chain audits—. Tener el comando incorporado al gestor evita la dependencia de tools externas como syft o cdxgen.
  • pnpm peers check — valida que todas las peer dependencies declaradas estén satisfechas. Hasta ahora era un dolor de cabeza típico que terminaba en runtime; ahora se chequea explícitamente.
  • pnpm runtime set — instala una versión específica de Node.js como runtime para el workspace. Por primera vez, pnpm gestiona el toolchain completo, no solo los paquetes.
  • pnpm with — ejecuta un comando con una versión específica de pnpm en una sola invocación, útil para troubleshooting de migraciones.
  • pnpm pack-app — empaqueta una aplicación Node.js como Single Executable Application (la API SEA agregada en Node.js reciente), produciendo un binario standalone. Este comando solo es ergonomía, no magia: el upstream de Node se hace cargo del verdadero trabajo.
  • Aliases pnpnpm y pnxpnpm dlx. Para gente que escribe pnpm cien veces al día, dos teclas menos por comando es un cambio real.

La pregunta operativa: ¿npm y Yarn van a seguir el camino?

A marzo de 2026, ni npm ni Yarn bloquean por defecto los lifecycle scripts ni implementan algo equivalente al minimumReleaseAge. La asimetría es importante porque significa que un equipo que usa npm o Yarn como gestor primario no tiene esta línea de defensa, salvo que la configure manualmente —cosa que la mayoría no hace, porque las defaults siguen siendo seguir el comportamiento histórico—.

El argumento del equipo de pnpm, articulado en su post de diciembre de 2025 sobre cómo protegieron su propio newsroom, es que los defaults son la línea de defensa real. Una configuración avanzada que el 90% de los usuarios no aplica no protege al 90%. Un default seguro sí. La objeción del campo opuesto es que defaults agresivos rompen workflows establecidos —y de hecho minimumReleaseAge rompe pnpm install cuando un mantenedor publica una versión legítima que tu equipo necesita ya—.

El balance final dependerá de cómo evolucione el panorama de ataques. Si los próximos seis meses traen otra campaña al estilo Mini Shai-Hulud o Contagious Interview, la presión sobre npm y Yarn para seguir el camino se vuelve casi imposible de resistir. Si los ataques se desplazan hacia otros vectores —tokens robados, compromiso de CI/CD, dependencias firmadas pero pre-comprometidas— las defensas de pnpm 11 quedan como una capa más en una defensa por capas, no como la solución definitiva.

Cómo actualizar

Para usuarios que ya tienen pnpm instalado:

# Self-update si tenés pnpm 10.x instalado
pnpm self-update next-11

# O instalación limpia desde npm (si aún no tenés Node 22)
nvm install 22
nvm use 22
npm install -g pnpm@latest

# Verificar
pnpm --version
# 11.0.0 (o superior)

Para CI: actualizar la imagen base a una con Node 22+, actualizar las versiones especificadas en packageManager field del package.json raíz, y revisar que el lockfile se regenere correctamente:

{
  "packageManager": "[email protected]"
}

Si tu organización maneja varios proyectos, el patrón conservador es probar pnpm 11 en uno solo durante una semana, especialmente con los nuevos defaults activos, y validar que los pipelines de CI no se rompan por el verifyDepsBeforeRun o el strictDepBuilds. Luego propagar al resto.

Lección de fondo

Hay una pregunta más amplia detrás de esta release que vale la pena retener. ¿Quién es responsable de la seguridad de la cadena de suministro en software open source? Durante años la respuesta implícita fue: el desarrollador individual que mantiene el lockfile. Lo cual era una abstracción cómoda pero falsa. Un proyecto típico de 2026 tiene cientos de dependencias directas y miles transitivas; auditar cada actualización es trabajo de tiempo completo.

pnpm 11 propone un modelo diferente: la seguridad razonable debe estar embebida en el gestor, no como configuración opcional sino como default. La filosofía es paralela a lo que pasó con HTTPS: durante años fue opt-in y la mayoría de los sitios lo dejaba off; cuando los browsers empezaron a marcar HTTP como inseguro y los deployment platforms a hacer HTTPS automático, la situación cambió. Lo que no se hace por defecto, no se hace en escala.

La otra lección es de cadencia política. pnpm es un proyecto open source mantenido por un puñado de personas; sin embargo, ha movido la frontera del comportamiento por defecto del ecosistema npm más que cualquier discusión en TC39 o cualquier RFC del registry. El cambio incremental por defaults agresivos ha resultado más efectivo que la reforma centralizada. Para quien está construyendo herramientas, ese es un patrón a estudiar: no esperes consenso, ofrecé una alternativa con defaults sustancialmente mejores y dejá que la migración hable.

Y para quien usa pnpm hoy: upgrade.

Fuentes

Categorías: Programación

Andrés Morales

Desarrollador e investigador en inteligencia artificial. Escribe sobre modelos de lenguaje, frameworks, herramientas para devs y lanzamientos open source. Cubre papers de ML, ecosistema de startups tech y tendencias de programación.

0 Comentarios

Deja un comentario

Marcador de posición del avatar

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.