Un mantenedor de un paquete con millones de descargas semanales abre un email que parece de soporte de npm, mete sus credenciales y, al día siguiente, su paquete publica una versión que roba tokens a todo el que la instala. No es un guion de película: es el patrón que se repite trimestre sí, trimestre también, con phishings cada vez más finos. Y no hace falta tener un paquete famoso para salir perdiendo: basta con una dependencia que se actualice sola en tu CI.
GitHub lleva meses desplegando cambios en npm y Actions para cortar esas cadenas de ataque, y esta semana ha publicado un repaso de todo lo que ya está en producción. La buena noticia: la mayoría de esas defensas son gratuitas y se activan con configuración, no con infraestructura nueva.
La mala: muchas son opt-in, y si nadie las activa en tu proyecto, no existen. Así que en vez de resumir la noticia, aquí va lo que puedes aplicar hoy, punto por punto, con los enlaces a la documentación oficial de cada medida. Si solo tienes diez minutos, ve directo al punto 1.

Así roban tu paquete: la cadena de ataque en 30 segundos
El patrón se repite: el atacante compromete la cuenta de un mantenedor o cuela código en un workflow de CI, desde ahí exfiltra credenciales (tokens de npm, secrets del pipeline), y con esas credenciales publica versiones maliciosas que se propagan a cientos de proyectos antes de que nadie reaccione. GitHub lo divide en tres fases: compromiso inicial, exfiltración de credenciales y propagación. Cada medida que sigue rompe una de esas fases.
1. Publica paquetes sin tokens: trusted publishing con OIDC
La medida con mejor ratio esfuerzo/impacto: eliminar el token de npm de larga duración que vive en los secrets de tu CI. Con trusted publishing, tu workflow se autentica contra npm con OIDC: tokens efímeros, firmados, válidos solo para ese workflow concreto. No hay nada que robar.
Funciona con GitHub Actions, GitLab CI/CD y, desde abril, CircleCI. Necesitas npm CLI 11.5.1+ y Node 22.14.0+. Se configura en dos pasos: en npmjs.com (Settings del paquete → Trusted Publisher) declaras organización, repo y nombre del fichero de workflow; y en el workflow añades el permiso OIDC:
permissions:
id-token: write # imprescindible para OIDC
contents: read
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm publish # sin NODE_AUTH_TOKEN, sin secrets
Dos detalles importantes de la documentación: publicando así desde un repo público se genera provenance automáticamente (prueba criptográfica de dónde y cómo se construyó el paquete), y una vez migrado deberías ir a Settings → Publishing access y marcar “Require two-factor authentication and disallow tokens” para que los tokens clásicos dejen de funcionar en ese paquete. Ah, y solo se permite un trusted publisher por paquete.
2. Staged publishing: que las credenciales de CI no basten para publicar
Si quieres ir un paso más allá, el staged publishing (opt-in, disponible desde mayo) desacopla “tener credenciales” de “publicar”: el paquete queda en staging hasta que un mantenedor lo aprueba con 2FA desde la CLI o npmjs.com. La combinación que recomienda la propia documentación de npm es configurar el trusted publisher solo con permiso de npm stage publish (sin npm publish), de modo que todo lo que sale del CI necesita aprobación humana antes de ser público. Si te roban el pipeline, el atacante se queda a un paso de nada.
3. npm v12: los scripts de instalación se apagan por defecto
La vía favorita de propagación de este malware no es el código del paquete en runtime, sino los scripts preinstall/postinstall: se ejecutan en cuanto haces npm install, antes de que nadie haya leído nada. Con npm v12 cambian tres defaults:
allowScriptspasa a off: ninguna dependencia ejecuta scripts de instalación salvo que la apruebes explícitamente. Esto incluye los builds implícitos denode-gyp.--allow-gitpasa anone: no se resuelven dependencias desde Git salvo opt-in.--allow-remotepasa anone: lo mismo para tarballs por URL remota.
Para prepararte, actualiza a npm 11.16.0 o superior y revisa los warnings de tu instalación habitual. El flujo es:
# Ver qué paquetes tienen scripts pendientes de aprobación
npm approve-scripts --allow-scripts-pending
# Aprobar los que confías / denegar el resto
npm approve-scripts
npm deny-scripts
La lista resultante se escribe en package.json y se commitea, así la decisión es auditable en code review. Si hoy instalas con --ignore-scripts en CI por costumbre, v12 simplemente convierte esa cautela en el comportamiento por defecto de todo el mundo.
4. GitHub Actions: cierra los pwn requests
En el lado del CI, los cambios de junio atacan el patrón de “pwn request”: un workflow con pull_request_target que hace checkout del código del fork y lo ejecuta con permisos elevados. Tres cosas a revisar:
- actions/checkout ya no descarga código de forks por defecto en los triggers habitualmente explotados; tienes que hacer opt-out explícito para volver al comportamiento inseguro. Si tu workflow dependía de eso, te toca revisarlo: es casi seguro que estabas expuesto.
- Políticas de ejecución de workflows: a nivel de repo, organización o empresa puedes limitar quién dispara workflows y qué tipos de trigger están permitidos. Si ningún workflow tuyo necesita
pull_request_target, desactívalo de golpe. - Caché de Actions en solo lectura para triggers no confiables: un workflow poco privilegiado ya no puede envenenar la caché que comparte con tu workflow de release.
Y lo de siempre, que sigue siendo gratis: declara permissions: mínimos en cada workflow (el GITHUB_TOKEN nace con demasiados permisos si no dices nada), fija las actions por SHA de commit y no por tag, y revisa quién puede modificar .github/workflows/. Todo esto está en la guía oficial de hardening de Actions.
5. Dependabot: el cooldown de tres días ya viene de serie
Desde el 14 de julio, Dependabot espera al menos tres días desde que una versión se publica antes de abrir la PR de actualización. La lógica es que estos ataques dependen de la velocidad: si una versión maliciosa se detecta y retira en 48 horas, un cooldown de 3 días te salva sin que hagas nada. Las actualizaciones de seguridad siguen abriéndose al momento.
Si quieres otro valor (más días, o distinto por tipo de bump), se configura con la opción cooldown en dependabot.yml:
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
cooldown:
default-days: 5
semver-major-days: 10
6. Para cuando algo sale mal
Dos herramientas de respuesta que conviene conocer antes de necesitarlas: la API de revocación de credenciales ahora cubre también tokens de OAuth y de GitHub Apps (nació en 2025 solo para PATs), y los administradores de empresa tienen revocación self-service de todas las credenciales de un usuario. Además, npm pone las cuentas de alto impacto en modo solo-lectura durante 72 horas si cambian el email o usan un código de recuperación de 2FA, justo la ventana que usan los phishings para publicar antes de que el mantenedor reaccione.
Y si gestionas una organización, echa un ojo al firewall de red para Actions (technical preview): registra todo el tráfico saliente de tus workflows, que es exactamente donde se ve una exfiltración.
La checklist, resumida
- Migrar la publicación a trusted publishing (OIDC) y prohibir tokens en el paquete.
- Activar staged publishing si el paquete es crítico.
- Actualizar a npm 11.16+, revisar warnings y generar la allowlist de scripts con
npm approve-scripts. - Revisar workflows con
pull_request_target; aplicar políticas de ejecución ypermissions:mínimos. - Configurar
cooldownendependabot.ymlsi el default de 3 días no te encaja. - Guardar los enlaces de revocación de credenciales en tu runbook de incidentes.
Nada de esto cuesta dinero ni exige herramientas nuevas: es configuración que ya está disponible en tu cuenta. La diferencia entre salir en las noticias como víctima o ni enterarte de que hubo un intento es, literalmente, un rato de configuración. El próximo ataque a la cadena de suministro no va a esperar a que lo programes en el sprint, así que yo empezaría por el punto 1 esta misma semana. Si quieres reforzar otras capas de seguridad, también te interesa cómo bloquear bots de IA en Cloudflare sin perder SEO y proteger aplicaciones web gratis con SafeLine WAF.
Preguntas frecuentes
¿Trusted publishing funciona con runners self-hosted?
No. Por ahora solo con runners hospedados por GitHub, runners compartidos de GitLab.com y CircleCI cloud, según la documentación de npm. El soporte para self-hosted está previsto pero sin fecha.
¿npm v12 romperá mis builds?
Si tus dependencias usan scripts de instalación (esbuild, sharp, bcrypt y otros paquetes con binarios nativos), sí: tendrás que aprobarlos con npm approve-scripts. Por eso conviene actualizar a 11.16+ ya, leer los warnings y commitear la allowlist antes de dar el salto a la v12.
¿El cooldown de Dependabot retrasa los parches de seguridad?
No. El cooldown de tres días aplica solo a actualizaciones de versión. Las actualizaciones de seguridad se abren inmediatamente, igual que antes.



¿Qué te ha parecido?
Déjame tu opinión, pregunta o sugerencia. Los comentarios se sincronizan con GitHub Discussions .