Si crees que lo peligroso sucede cuando tu código ya está en producción, hoy te voy a pinchar ese globo con una idea clave: la infección puede empezar al instalar. No hace falta “ejecutar” tu app, ni siquiera importarla.
En ataques de cadena de suministro, basta con que alguien haga un npm install en el lugar equivocado (tu portátil, un runner de CI, un build server). A partir de ahí, el atacante busca lo que más vale: credenciales y secretos.

¿Qué significa que un canal “oficial” de npm se comprometa?
Cuando confías en un namespace o una organización “verificada”, estás comprando algo más que código: estás comprando confianza operativa. Y esa confianza se convierte en un acelerador del daño si cae la cuenta que publica.
El patrón suele repetirse: acceso a una cuenta con permisos, publicación rápida de versiones nuevas, y mucha gente actualizando sin mirar. Lo doloroso es que no hace falta un 0‑day, a veces basta con credenciales robadas.
Aquí hay una lección práctica: tu modelo de amenaza no puede ser solo “mi repo está bien”. Tiene que incluir mis dependencias y mis canales de publicación (npm, GitHub Actions, registries privados).
Si tu equipo usa paquetes internos, namespaces y automatizaciones, revisa esta frase: la identidad del publicador es un activo. Protegerla es tan importante como proteger el código.
Idea rápida: en supply chain, la puerta no es tu app, es tu pipeline.
Si el atacante entra en quien publica, entra indirectamente en quien instala (y eso es impacto en cadena).

¿Por qué el riesgo empieza en la instalación y no en el runtime?
Mucho malware moderno se engancha a scripts de instalación. Eso significa que al instalar un paquete puedes disparar acciones en tu máquina con permisos del entorno de build (que suelen ser más altos de lo que crees).
Por eso da igual que tu app nunca llegue a levantar un servidor. Si el script corre en un runner con acceso a variables, el atacante ya puede leer tokens de CI, llaves y credenciales.
Otra trampa mental es pensar “solo fue en desarrollo”. En realidad, desarrollo es donde viven los secretos útiles: repos, registries, nubes y despliegues. Eso es justo lo que un atacante quiere.
Si además tienes builds automáticos, el impacto escala solo. Un solo commit que actualiza dependencias puede disparar instalaciones en múltiples runners. Y ahí aparece lo feo: propagación silenciosa.
La conclusión práctica: trata la instalación como un momento de alto riesgo y pon controles ahí. No lo dejes para producción.
¿Cómo se propaga un gusano de supply chain dentro de CI/CD?
Piensa en un gusano como en un vendedor agresivo con agenda: roba secretos y busca dónde más puede publicarse. Si encuentra un token con permisos, intenta replicar el ataque en otros repos.
En CI/CD el objetivo no es “romper tu web”, es moverse lateralmente: de un repo a otro, de una org a otra, de un registry a otro. Con cada salto, el atacante gana más alcance.
El motivo es simple: los pipelines están diseñados para automatizar. Esa automatización (bien usada) da velocidad al equipo, pero (mal defendida) da velocidad al atacante.
Si usas GitHub Actions u otros runners, revisa el uso de OIDC y credenciales temporales. Son buenas prácticas, pero no son magia. La pregunta real es: ¿quién puede pedir esos tokens y desde dónde?
Y ojo con una confusión típica: “como son tokens temporales, da igual”. No. Un token temporal puede ser suficiente para publicar un paquete o tocar un secret si la política lo permite.
- Robo de secretos desde variables de entorno y ficheros de configuración
- Exfiltración a un servidor externo (o a un canal alternativo si falla)
- Reutilización de tokens para publicar nuevas versiones maliciosas
- Persistencia suave (dejar puertas para repetir el ataque)
- Escalada de confianza (más repos, más organizaciones, más impacto)
¿Qué señales rápidas puedes revisar hoy mismo (sin volverte loco)?
Si sospechas que has instalado algo comprometido, actúa como si ya te hubiesen leído secretos. El primer objetivo es acotar el intervalo de exposición: qué máquinas y qué pipelines lo ejecutaron.
Revisa el lockfile (package-lock.json, pnpm-lock.yaml o yarn.lock). Cambios raros en dependencias transitivas y versiones “improvisadas” son un síntoma. Pero lo más útil es mirar el historial de instalaciones en CI.
Busca conexiones salientes anómalas desde runners, sobre todo durante la fase de instalación. Si puedes, captura logs de red. La pista no siempre está en tu repo, sino en tu infraestructura de build.
Mira también tu registry: ¿hubo publicaciones fuera de horario?, ¿se publicaron múltiples versiones en minutos?, ¿aparecen autores desconocidos? Son señales de cuenta comprometida.
Y algo muy simple que funciona: lista todos los tokens con permisos de publicación y anota dónde viven. Si no puedes responder eso en 10 minutos, tienes un problema de inventario de secretos.
Regla de oro: en incidentes de supply chain, lo urgente es rotar secretos, no buscar “el archivo exacto”.
La rotación corta la propagación, incluso si todavía no entiendes todo el alcance (prioriza cortar accesos).
¿Cómo contener el daño sin parar toda la empresa?
Contener no es apagar Internet. Contener es cortar caminos de abuso. Empieza por lo obvio: rota tokens de publicación (npm, registries privados) y revoca credenciales de CI que no necesitas.
Segundo: aísla runners. Si un runner tiene acceso a demasiados secretos, convierte un incidente en un incendio. Aplica el principio de mínimo privilegio por workflow (no por organización entera).
Tercero: revisa qué repos tienen permisos de escribir en otros repos (o de publicar). Ese tipo de permisos cruzados es el fertilizante perfecto para un gusano. Reduce el radio de explosión.
Cuarto: limpia cachés de dependencias en CI, pero hazlo con intención. Si borras todo sin plan, pierdes evidencia. Mejor: congela logs y artefactos primero, luego limpia.
Quinto: define una ventana de “solo builds esenciales”. Esto baja ruido y te permite verificar. El objetivo no es castigar al equipo, es ganar control del sistema.
- Revocar tokens de npm y regenerarlos con 2FA
- Rotar secretos de cloud (Kubernetes, Vault, proveedores)
- Revisar permisos de publicación y owners en registries
- Bloquear egress desde runners a destinos no permitidos
- Auditar workflows que imprimen variables o usan debug
¿Qué políticas te protegen sin matar la productividad del equipo?
La seguridad útil es la que se integra en el flujo. Por ejemplo: firmas y verificación de provenance (cuando sea posible) ayudan, pero lo básico sigue siendo gestión de identidades y permisos.
Empieza por separar identidades humanas y de automatización. Un humano no debería publicar con el mismo token que un workflow. Eso facilita rotación y reduce el daño. Una cuenta por propósito.
Luego, limita quién puede publicar y desde dónde. Si tu pipeline publica, que sea desde un entorno controlado, con permisos mínimos y revisiones. Evita “publicar desde laptops”. Centraliza el release.
Otra capa potente es exigir revisiones para cambios de dependencias. No para todo, pero sí para cambios en scripts, postinstall o paquetes sensibles. Esto crea una fricción pequeña que bloquea ataques baratos.
Por último, mide. Si no tienes métricas de dependencia (qué se instala, cuándo, dónde), vas a improvisar en cada incidente. Y en incidentes, improvisar sale caro. Métricas antes que drama.
Política sencilla: “ningún workflow puede acceder a todos los secretos”.
Divide secretos por repos, por entorno y por necesidad real (aplica mínimo privilegio).

¿Qué checklist pasar antes de volver a “confiar” en npm?
Si te quedas con una sola idea, que sea esta: la confianza no es binaria. Se gestiona. Y se gestiona con procesos repetibles. Checklist o caos.
Antes de reanudar el ritmo normal, valida que tus rotaciones están completas. Muchos equipos rotan “lo obvio” y se olvidan de tokens secundarios. Eso es lo que permite reinfecciones. Sin excepciones raras.
Después, revisa dependencias directas y transitivas en los proyectos críticos. No hace falta auditar el planeta, pero sí lo que impacta despliegues. Prioriza por exposición. Riesgo primero.
Finalmente, documenta lo aprendido. No como un PDF muerto, sino como cambios en workflows y permisos. Si no aterriza en el repositorio, se olvida. Lecciones en código.
Truco práctico: crea un “modo incidente” para CI.
Un flag que reduzca permisos y egress cuando algo huele mal (para frenar la propagación).
- Inventario de tokens y rotación verificada (npm, GitHub, cloud)
- Revisión de owners y permisos de publicación por namespace
- Bloqueo temporal de instalaciones no esenciales en CI
- Escaneo de runners (procesos, conexiones, artefactos)
- Reapertura gradual con monitorización y alertas
¿Qué cambia si tú también publicas paquetes (open source o internos)?
Si mantienes paquetes, tu prioridad no es solo que el código sea bueno, sino que la cuenta que publica sea difícil de secuestrar. En la práctica eso significa identidades separadas y procesos repetibles, no “acceso compartido”.
Evita publicar desde el navegador o desde equipos personales sin controles. Publica desde un pipeline controlado con permisos mínimos, y deja el “botón de release” donde puedas auditarlo. Release centralizado.
También es importante reducir la “superficie humana”. Si 12 personas pueden publicar, basta una credencial filtrada para comprometer el canal. Limita publishers y usa revisiones. Menos llaves, más control.
Y ojo con los accesos heredados. Tokens viejos, cuentas de ex-empleados, y permisos que quedaron “por si acaso” son una bomba lenta. Haz un calendario: revocar por defecto y reautorizar lo necesario.
Por último, comunica rápido cuando pasa algo. No hace falta dar detalles peligrosos, pero sí dar instrucciones claras para consumidores (qué versiones evitar, cómo comprobar, cómo rotar). Comunicación accionable.
Señal de alerta: si “nadie sabe” quién puede publicar, ya vas tarde.
La gobernanza de publicación es parte de la seguridad, no un detalle administrativo (es control de acceso).
- 2FA obligatorio y tokens de publicación rotados por periodo
- Cuenta de publicación dedicada (no la cuenta personal del maintainer)
- Publicación desde CI con permisos mínimos y logs guardados
- Revisión extra para cambios en scripts de instalación
- Owner audit mensual (quién puede publicar y por qué)
¿Cómo montar un pipeline más resistente en 30 días (sin reescribirlo todo)?
La mayoría de equipos no necesita un “proyecto de seguridad” de seis meses. Necesita una secuencia corta de cambios que bajen riesgo de forma visible. Llámalo plan de 30 días. Pequeños cambios, gran impacto.
Día 1 a 7: inventario y permisos. Enumera secretos, dónde están y qué workflows los usan. Luego divide por entorno (dev, staging, prod). El objetivo es sencillo: cada workflow con lo mínimo.
Día 8 a 15: controles de instalación. Añade políticas para evitar scripts peligrosos donde no hagan falta, y fija reglas para lockfiles. Si usas cache de dependencias, decide cuándo se invalida. Instalación controlada.
Día 16 a 23: observabilidad de CI. Guarda logs de instalaciones, red y artefactos en un lugar central. No es “por paranoia”, es para poder responder en horas y no en semanas. Visibilidad operativa.
Día 24 a 30: simulacro y modo incidente. Define un runbook, prueba rotación de tokens y un flag para bajar permisos y egress. Cuando lo practicas en calma, no improvisas en fuego. Ensayo antes del incidente.
Objetivo realista: que un ataque no pase de “incidente” a “crisis”.
Reducir radio de explosión y ganar trazabilidad es más valioso que prometer perfección (busca resiliencia operativa).
- Semana 1: inventario de secretos y recorte de permisos
- Semana 2: reglas de dependencias y revisión de lockfiles
- Semana 3: logs centralizados y alertas de publicaciones raras
- Semana 4: runbook, simulacro y “modo incidente” en CI
¿Cómo explicárselo a un equipo no técnico?
Si tienes que contárselo a dirección o a producto, evita tecnicismos.
Metáfora de proveedores.
Di algo como: “hemos detectado un riesgo en un proveedor de piezas (dependencias) y estamos rotando llaves y revisando la cadena de entrega”.
Plan antes que miedo.
Explica el impacto en términos de negocio: exposición de credenciales, acceso a repos, riesgo de interrupción. Y aclara el plan: contención, rotación, verificación. Eso reduce ansiedad y evita decisiones impulsivas.
Hitos claros.
También ayuda dar un indicador simple: “qué necesitamos para volver a la normalidad”. Por ejemplo, “rotación completa y verificación de pipelines críticos”. La gente entiende hitos.
Transparencia útil.
Y sé honesto con lo incierto.
En supply chain puede haber zonas grises al principio. Lo importante es que estás cortando la propagación y reduciendo superficie.